Posts: 66
Threads: 28
Joined: Aug 2017
So I am learning classes in python and I stumbled across something that did not make sense to me.
In the code below, when I change the name of the student via calling the method changeName passing the new parameters (forename and surname), why doesn't it reflect the changes when I print the attribute fullname?
class Student:
def __init__(self, forename, surname):
self.forename = forename
self.surname = surname
self.fullname = self.forename + " " + self.surname
def changeName(self, forename, surname):
self.forename = forename
self.surname = surname
s1 = student("billy", "smith")
print(s1.fullname)
s1.changename("tom", "jones")
print(s1.fullname) ----> why is this not updating?
Posts: 1,145
Threads: 114
Joined: Sep 2019
May-31-2020, 01:00 PM
(This post was last modified: May-31-2020, 01:00 PM by menator01.)
Check your spelling
your not return fullname in changeName
class Student:
def __init__(self, forename, surname):
self.forename = forename
self.surname = surname
self.fullname = self.forename + " " + self.surname
def changeName(self, forename, surname):
self.forename = forename
self.surname = surname
self.fullname = f'{self.forename} {self.surname}'
return self.fullname
s1 = Student('Billy','Smith')
print(s1.fullname)
s1.changeName('Tom','Jones')
print(s1.fullname) Output: Billy Smith
Tom Jones
Posts: 66
Threads: 28
Joined: Aug 2017
There's nothing grammatically wrong with the spelling in my code.
You pointed out that I need to declare self.fullname again in the method and then it works. Although you are correct, it just doesn't make any sense since all that the self.fullname does is basically print out the values of self.forename and self.surname and these are being changed in the method so I would have thought python would be smart enough to work with the latest values assigned to these attributes, hence i was expecting self.fullname to print out the updated name without the need to explicitly declare it again.
Posts: 8,160
Threads: 160
Joined: Sep 2016
May-31-2020, 02:02 PM
(This post was last modified: May-31-2020, 02:03 PM by buran.)
fullname is property like any other, it's not linked to forename and surname (i.e. updated when forname and surname change)
To achieve what you want you need to use @property decorator in this case and get the Student.fullname from Student.forename and Student.surname. Also, note that you don't really need changeName method.
class Student:
def __init__(self, forename, surname):
self.forename = forename
self.surname = surname
@property
def fullname(self):
return f"{self.forename} {self.surname}" # using f-string or str.format() is better than string concatenation"
def change_name(self, forename, surname):
self.forename = forename
self.surname = surname
s1 = Student('Billy','Smith')
print(s1.fullname)
s1.change_name('Tom','Jones')
print(s1.fullname)
# no need of change_name
s1.forename = 'Jake'
print(s1.fullname)
s1.fullname = 'Jane Doe' Output: Billy Smith
Tom Jones
Jake Jones
Traceback (most recent call last):
File "/home/boyan/sandbox2/forum.py", line 23, in <module>
s1.fullname = 'Jane Doe'
AttributeError: can't set attribute
as you can see, now you cannot change fullname directly
Posts: 6,792
Threads: 20
Joined: Feb 2020
The problem is caused by not executing the code that generates fullname.
One way to solve this problem is to recompute fullname any time you change forename or surname (duplicate some code from the init method). Another solution is to recompute fullname any time you ask for it.
def __init__(self, forename, surname):
self.forename = forename
self.surname = surname
def fullname()
return self.forename + " " + self.surname If you want fullname to look like a class variable instead of a function you can use a property decorator.
@property
def fullname()
return self.forename + " " + self.surname A nice thing about this approach is that fullname is guaranteed to always be forename followed by surname. Unlike the original code a user of your class cannot set the fullname independently of the forename or surname.
Posts: 2,168
Threads: 35
Joined: Sep 2016
(May-31-2020, 02:02 PM)buran Wrote: as you can see, now you cannot change fullname directly
Unless you wanted to add a setter then you could change fullname like this.
class Student:
def __init__(self, forename, surname):
self.forename = forename
self.surname = surname
@property
def fullname(self):
return f"{self.forename} {self.surname}" # using f-string or str.format() is better than string concatenation"
@fullname.setter
def fullname(self, full_name):
self.forename, self.surname = full_name.split(' ')
s1 = Student('Billy','Smith')
print(s1.fullname)
s1.fullname = 'Tom Jones'
print(s1.fullname)
s1.forename = 'Jake'
print(s1.fullname)
s1.fullname = 'Jane Doe'
print(s1.fullname) Output: Billy Smith
Tom Jones
Jake Jones
Jane Doe
Posts: 8,160
Threads: 160
Joined: Sep 2016
May-31-2020, 04:01 PM
(This post was last modified: May-31-2020, 04:02 PM by buran.)
(May-31-2020, 03:51 PM)Yoriz Wrote: Unless you wanted to add a setter then you could change fullname like this. yes, of course, one can create setter and manipulate forename and surname respectively. Good point
Posts: 353
Threads: 13
Joined: Mar 2020
Also remember - once you define something in python you got to use the exact same word with changing anything in its structure - Python is sensitive about that
Posts: 66
Threads: 28
Joined: Aug 2017
Jun-09-2020, 06:13 PM
(This post was last modified: Jun-09-2020, 06:14 PM by mp3909.)
Ok, thanks guys, much appreciated.
I seen elsewhere that the property decorators are ditched and written like this sometimes:
class C(object):
def getx(self): return self._x
def setx(self, value): self._x = value
def delx(self): del self._x
x = property(getx, setx, delx, "I'm the 'x' property.") I was trying to write the below code using the above implementation but not sure how?
class Employee:
def __init__(self, first, last):
self.first = first
self.last = last
@property
def fullname(self):
return f"{self.first} {self.last}"
@fullname.setter
def fullname(self, name):
first, last = name.split(" ")
self.first = first
self.last = last
@fullname.deleter
def deleter(self):
print("Delete Name")
self.first = None
self.last = None
emp_1 = Employee("john", "smith")
emp_1.fullname = "bill adams"
print(emp_1.first)
print(emp_1.last)
print(emp_1.fullname) Also, which implementation is most widely used in practice?
Posts: 6,792
Threads: 20
Joined: Feb 2020
Jun-10-2020, 02:16 AM
(This post was last modified: Jun-10-2020, 02:16 AM by deanhystad.)
Getters and setters are nice when binding your code to events. I haven't found a good way to use properties in GUI code. It may not be "Pythonic", but neither are Qt or GTK or Tk.
|