Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
244 views
in Technique[技术] by (71.8m points)

python - having some trouble and confusion in setter & @property decorator, not all attributes defined in `__init__` are updated

class Employee:
    def __init__(self,first,last,pay):
        self.first = first
        self.last = last
        self.pay = pay
        self.annual_pay = 12*pay
        self.email = self.first + '.' + self.last + '@email.com'

    @property                   
    def fullname(self):
        return ('{} {}'.format(self.first,self.last))

    @fullname.setter            
    def fullname(self,name):
        first,last = name.split(' ')
        self.first = first
        self.last = last

emp1 = Employee('test1','subject1',10000)
emp1.fullname='test2 subject2'
print(emp1.fullname)
print(emp1.email)

I used setter to assign user a fullname() and override the attributes set by init already on the top, but in the output it only changed fullname as test2 subject2 meanwhile email had been unchanged as [email protected] (i learned from a tutorial and i thought we can override default attributes by this setter functionality) (Also that guy didn't use email in init like I did but instead he had a separate function for it with @property decorater with it)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

That is because the value of email was computed and saved when you ran __init__(). Just because you change self.first and self.last doesn't mean self.email will be affected, because it is not saved in terms of its relationship to those variables. It is saved as a string.

Example:

a = "hello"
b = "world"
c = a + b
a = "goodbye"
print(c)
>>> "hello world"

Here, c was set to a+b and that value was saved when that line was executed. Changing a after we have already given c its value won't change it. It is already set, and we would have to do c = a+b again to get it to print out goodbye world.

In your case, you'd have to modify it in the setter:

@fullname.setter            
def fullname(self,name):
    first,last = name.split(' ')
    self.first = first
    self.last = last
    self.email = self.first + '.' + self.last + '@email.com'

However that is not good practice, as the setter should only change the specific variable you're accessing. That is why the tutorial you were reading had a function for email: If you want the it to be dynamically computed based on whatever the values of first and last are at the moment you check it, you should always use a function:

def email(self):
    return self.first + '.' + self.last + '@email.com'

print(emp1.email())

If you want, you can use the property decorator like the tutorial does:

@property
def email(self):
    return self.first + '.' + self.last + '@email.com'

This is just syntactical sugar to allow you to call it as before:

print(emp1.email)

Instead of having to call it like a function, even though that is all it is.

As a sidenote, I'd recommend using string formatting, which is generally preferred to using + to join strings together in cases like this:

return f"{self.first}.{self.last}@email.com"

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...