Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Python SQLAlchemy Basics Working with SQLAlchemy Creating Our Book Database

Andy McDonald
Andy McDonald
5,016 Points

Using variable as attribute

I started writing the following code:

def edit():
    toedit = str(input('What book do you want to edit'))
    part = input('What do you want to change about it? \nType number to select follwing: \n1. Title \n2. Author\n3. Published date\n4. Price\n')
    if part == '1':
        change = input('Okay, what do you want to change the title to?')
        bookie = models.session.query(models.Book).filter_by(title=toedit)
        for bkie in bookie:
            bkie.title = change
        print(bkie)

And repeated this block for each attribute of the object. And then realized I could make it real dry by only writing the bottom part of the block once and throwing some variables in there like so:

    elif part == '3':
        part = 'pubdate'
    change = input(f'Okay, who should I change the {part} to?')
    bookie = models.session.query(models.Book).filter_by(part=toedit)
    for bkie in bookie:
        bkie.part = change

This does not work because a variable cant be passed as an attribute. Or can it? Is there any way to make this work?

1 Answer

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 67,763 Points

Hey Andy McDonald, excellent question!

Using star notation, a dict can be used as keyword/pairs. If using part as a variable, the dict can be defined then expanded as kwargs.

# define
kwdict = {part: toedit}

# use as
bookie = models.session.query(models.Book).filter_by(**kwdict)

# then 
    for bkie in bookie:
        setattr(bkie, part, change)

Post back if you need more help. Good luck!!!

Andy McDonald
Andy McDonald
5,016 Points

Unless theres something I'm missing. I dont think this is valid syntax. I need to pass this as(attribute = 'value'}. Passing a key value pair would be more like ('key' : 'pair')

Chris Freeman
Chris Freeman
Treehouse Moderator 67,763 Points

I've created the following code. Save to a local file and run using python <filename>. It may help understand using the "star notation" to unpack a dictionary into attributes.

import datetime


class def_init:
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)

    def __str__(self):
        return f"my attributes are: {self.__dict__}"

part = "pub_date"
value1 = datetime.datetime.now()

kwarg_dict = {part: value1}

# line below shows that a dict will expand to
# key becoming the attribute and value becoming the attribute value
# **{part1: value1} becomes (pub_date=<datetime_object>)
print("\nCreating new instance using star notation for dict to kwargs")
print(f"kwargs are {kwarg_dict}")
an_instance = def_init(**kwarg_dict)
print(an_instance)
print(f"check attr pub_date: {an_instance.pub_date}")

outputs:

$ python dict_init.py 

Creating new instance using star notation for dict to kwargs
kwargs are {'pub_date': datetime.datetime(2021, 8, 6, 23, 14, 6, 941012)}
my attributes are: {'pub_date': datetime.datetime(2021, 8, 6, 23, 14, 6, 941012)}
check attr pub_date: 2021-08-06 23:14:06.941012
Andy McDonald
Andy McDonald
5,016 Points

I just realized how to use this and this next question is totally hypothetical: Lets say there's lots of dot notation stacked onto one object. How would you use setattr to do that for the last attribute? Is it just each attribute has its own positional argument with the last argument being what it is set equal to?

Chris Freeman
Chris Freeman
Treehouse Moderator 67,763 Points

Regarding setattr use, here’s some other examples:

class ThirdLevel:
    def __init__(self):
        self.color = "red"
        self.name = "3Level"

    def __str__(self):
        return self.name


class SecondLevel:
    def __init__(self):
        self.s_attr = ThirdLevel()
        self.name = "2Level"

    def __str__(self):
        return self.name


class TopLevel:
    def __init__(self):
        self.t_attr = SecondLevel()
        self.name = "TLevel"

    def __str__(self):
        return self.name

t = TopLevel()
print("1", t, t.t_attr, t.t_attr.s_attr, t.t_attr.s_attr.color)

target = t
setattr(target.t_attr.s_attr, "color", "blue")
print("2", t, t.t_attr, t.t_attr.s_attr, t.t_attr.s_attr.color)

deep = t.t_attr.s_attr
setattr(deep, "color", "green")
print("3", t, t.t_attr, t.t_attr.s_attr, t.t_attr.s_attr.color)

Outputs:

1 TLevel 2Level 3Level red
2 TLevel 2Level 3Level blue
3 TLevel 2Level 3Level green

Play around with this. Post back if you need more help. Good luck!!!

Andy McDonald
Andy McDonald
5,016 Points

ill get back to you in 4 weeks on that one