#๐ I think it's not a typo
82 messages ยท Page 1 of 1 (latest)
@echo cove
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
i don't see what's wrong?
thats a strange way to explain/show how to use property without it being a decorator
he create a public attribute in the init method but uses private attribute in the getter\
that is an older way
but he did set name = property(...)
ah
so when calling Person.name it would run the getter function
i wouldn't really recommended doing it this way
same
much clearer to use the decorator
it is a decorator... just completely laid out
if i called p.name , the init will be valid?
yes its still valid
what if i use decorators...then?
you can either use property as a decorator or just a plain property function call. Either way it works
but in previous code he uses private attr in the init
you could do it both ways but that would be complicating yourself
it is common to use a private attr
One thing to understand is there is no such thing as "private" btw. You can still access the _ attributes without the @property
yeah
!e
class Person:
def __init__(self, name):
self._name = name
p = Person("ajay")
print(p._name)
:white_check_mark: Your 3.14 eval job has completed with return code 0.
ajay
nothing, it is working...
but in this the private attr is also in the__init__
ok you wrote it
Sorry. I meant, what part of that is confusing you?
you chose p._name to call as you have written self._name...but in the first image in init it is self.name = name
and when he calls with self.name the getter still prints but getter have self._name. how is it possible of having both the __init__ and getter diff values but sa,e result
wait is it being called directly
because you have to use a separate attribute for doing the getter and setter since name is a property, you would do the logic for getters and setters differently. hang on a min
I will show a series of codes that will throw errors and I will do my best to explain it
ty
!e
class Person:
def __init__(self, name):
self.name = name # This will cause an AttributeError
@property
def name(self):
return self.name
p = Person("satyam")
print(p.name)
:x: Your 3.14 eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File [35m"/home/main.py"[0m, line [35m8[0m, in [35m<module>[0m
003 | p = Person("satyam")
004 | File [35m"/home/main.py"[0m, line [35m3[0m, in [35m__init__[0m
005 | [1;31mself.name[0m = name # This will cause an AttributeError
006 | [1;31m^^^^^^^^^[0m
007 | [1;35mAttributeError[0m: [35mproperty 'name' of 'Person' object has no setter[0m
The error here says "property 'name' of 'Person' object has no setter"
That should be obvious as the 'name' property is already decorated, it should have a getter and setter. In this case, the getter is already provided as return self.name but it doesn't know or have the logic to "set" a name
!e
If I add the setter, it looks like this:
class Person:
def __init__(self, name):
self.name = name
@property
def name(self):
return self.name
@name.setter
def name(self, new_name):
self.name = new_name
p = Person("satyam")
print(p.name)
:x: Your 3.14 eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File [35m"/home/main.py"[0m, line [35m11[0m, in [35m<module>[0m
003 | p = Person("satyam")
004 | File [35m"/home/main.py"[0m, line [35m3[0m, in [35m__init__[0m
005 | [1;31mself.name[0m = name
006 | [1;31m^^^^^^^^^[0m
007 | File [35m"/home/main.py"[0m, line [35m9[0m, in [35mname[0m
008 | [1;31mself.name[0m = new_name
009 | [1;31m^^^^^^^^^[0m
010 | File [35m"/home/main.py"[0m, line [35m9[0m, in [35mname[0m
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/GM3PEG36C7GMVYDWZ67FI2MZVM
But now, it throws a different error
File "/home/main.py", line 9, in name
self.name = new_name
^^^^^^^^^
[Previous line repeated 995 more times]
RecursionError: maximum recursion depth exceeded
Because it kept calling itself name attribute which is another getter which is also called name
So we basically confused it that the getter for name is also name. To break this recursion, we call the "private" attribute something different like _name, as thats not a decorated property that has a getter or setter
!e
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, new_name):
self._name = new_name
p = Person("satyam")
print(p.name)
:white_check_mark: Your 3.14 eval job has completed with return code 0.
satyam
It doesn't need to be _ as I pointed out earlier. You could use any other attribute name you want
!e
class Person:
def __init__(self, name):
self.temp_name = name
@property
def name(self):
return self.temp_name
@name.setter
def name(self, new_name):
self.temp_name = new_name
p = Person("satyam")
print(p.name)
:white_check_mark: Your 3.14 eval job has completed with return code 0.
satyam
but it is common to add _ to denote the property and the attr refer to the same thing or are closely related
right. thats the usual practice and common understanding between devs that when you want something considered as a "private" attribute in a class, you add a _ to it
And then its just as us devs to see and understand that and be like "ah, that attribute was written to be private. We should just respect that design and variable name as it is"
we need setter too? cant it run without setter
you can run without a setter but that would mean you've already set the value as soon as the class is initialized and skips the __init__
!e
class Person:
@property
def name(self):
return "satyam"
p = Person()
print(p.name)
p.name = "Ajay" #Tries to change to Ajay
print(p.name)
But by doing this, you can't edit the name property anymore.
:x: Your 3.14 eval job has completed with return code 1.
001 | satyam
002 | Traceback (most recent call last):
003 | File [35m"/home/main.py"[0m, line [35m8[0m, in [35m<module>[0m
004 | [1;31mp.name[0m = "Ajay" #Tries to change to Ajay
005 | [1;31m^^^^^^[0m
006 | [1;35mAttributeError[0m: [35mproperty 'name' of 'Person' object has no setter[0m
its the same if you tried in __init__ too
ok
!e
class Person:
def __init__(self):
self._name = "satyam"
@property
def name(self):
return self._name
p = Person()
print(p.name)
This works because you're not "setting" any new value. Its all hardcoded. And of course if you edit or set a new name after that, it throws that AttributeError like before
:white_check_mark: Your 3.14 eval job has completed with return code 0.
satyam
that looks straightforward... hang on. gimme a min
!e
class Person:
def __init__(self, name):
self.name = name # 1) This will set the name value into the self.name property as defined in the next line. But because its a property, it needs a setter.
@property
def name(self):
return self._name # 3) This is the last step. Because the value is already called and set in the setter, this self._name DOES have a value and thus is able to give back what the value is to the property.
@name.setter
def name(self, value):
self._name = value # 2) So when this class instantiates, the setter here will place the "name" value into the `self._name`
p = Person("ajay")
print(p.name)
:white_check_mark: Your 3.14 eval job has completed with return code 0.
ajay
So the flow goes from setting the "ajay" as an argument in the __init__, then because self.name = name triggers the self.name property's setter defined in @name.setter, it will set the value into self._name and then returns it to the property name
I've numbered them in the comments as 1) 2) and 3) for convenience
yes i read that,...
ok
got it
that was tricky
it worked
thank you @deft galleon
!close
This help channel has been closed. Feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.