Posts: 83
Threads: 33
Joined: Dec 2017
The following code works, as long as I use primarily public instance variables. When I change my public self.l to its private form self._l, the code breaks
class Emp():
def __init__(self, f, l):
self.f = f
self.l = l
self.e = self.f + self.l +'@gmail.com'
@property
def fullname(self):
return '{} {}'.format(self.f, self.l)
@fullname.setter
def fullname(self, name):
f,l=name.split(' ')
self.f = f
self.l = l
@fullname.deleter
def fullname(self):
print('deleted')
self.f = None
self.l = None
emp1 = Emp('Foo','Bar')
emp2 = Emp('Moo','Soo')
emp2.l='foo'
print(emp2.f)
print(emp1.l)
print(emp1.fullname)
del emp2.fullname I get a traceback error:
Quote:Traceback (most recent call last):
File "decs1.py", line 30, in <module>
print(emp1.l)
AttributeError: 'Emp' object has no attribute 'l'
Also: can anyone concisely explain the purpose behind @property decorators in general and @classmethod? From what I understand of them, both seem to basically offer another way to instantiate objects. I haven't used any examples of @classmethod, but the only use I see for them is to let me run something like @fooclass.deleter to delete instances on a case by case basis.
Posts: 100
Threads: 3
Joined: Dec 2017
The code you posted works. Please post the code that doesn't.
As your fullname shows, the @property decorator enables you to implement logic when accessing class fields and not refer to them as functions. They also enable you to create "read only" properties (simply omit the @property.setter method).
I'm not sure that @classmethod can be concisely explained. It's one of those "useful when you need it but you don't need it often" kinds of features. I don't really know it, and subsequently don't use it.
And please, for the love of God, NEVER use l as a variable name. In general, single-letter variable names should be avoided but l is the worst because it looks too much like 1.
Posts: 2,953
Threads: 48
Joined: Sep 2016
The first argument passed to the @classmethod decorated method is the class object ( cls ), not the instance object ( self ). It cannot modify an instantiated object.
Posts: 325
Threads: 11
Joined: Feb 2010
(Jan-09-2018, 05:59 PM)mepyyeti Wrote: Quote:Traceback (most recent call last):
File "decs1.py", line 30, in <module>
print(emp1.l)
AttributeError: 'Emp' object has no attribute 'l' There is nothing special about "private" variables.
If you have named it _l , that's its name, you can't call it l in the rest of your code.
(Jan-09-2018, 05:59 PM)mepyyeti Wrote: Also: can anyone concisely explain the purpose behind @property decorators in general and @classmethod? From what I understand of them, both seem to basically offer another way to instantiate objects. I haven't used any examples of @classmethod, but the only use I see for them is to let me run something like @fooclass.deleter to delete instances on a case by case basis. A classmethod is a method which is meant to be called on the class itself instead on an instance of this class (and it receives the class as its first argument.
The most common usage for them is alternate constructors.
A property is a way to crate a descriptor, which is basically an object whose attribute access (getting, setting, or deleting) has been replaced with special methods ( __get__ , __set__ , __delete__ ).
You would use a property you need to perform some additional action (e.g. validation) when you access the property in one of those 3 ways.
They are most commonly used if you're changing your code to require additional logic, but don't want to change the API.
If you need that logic from start, it is usually better to just write a method.
Posts: 83
Threads: 33
Joined: Dec 2017
So I've learned self.foo = public, self._foo=private, self.__=protected and self._foo is more or less best practice
ok anyway I guess I should have been clearer. The code works for self.foo but breaks with self._foo.
This code will break for example. See below thx:
class Emp():
def __init__(self, first, last):
self._first = first
self._last = last
self.e = self._f + self._l +'@gmail.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
@fullname.deleter
def fullname(self):
print('deleted')
self.first = None
self.last = None
emp1 = Emp('Foo','Bar')
emp2 = Emp('Moo','Soo')
emp2._last='foo'
print(emp2._first)
print(emp1._last)
print(emp1.fullname)
del emp2.fullname I've experimented with this considerably and found that self._ is fine but self._last ALWAYS breaks...what am I missing.
Quote:Traceback (most recent call last):
File "propstest0.py", line 24, in <module>
emp1 = Emp('Foo','Bar')
File "propstest0.py", line 6, in __init__
self.e = self._f + self._l +'@gmail.com'
AttributeError: 'Emp' object has no attribute '_f'
self.foo to self._foo is the only change in the code...idk why it has this effect...
Posts: 100
Threads: 3
Joined: Dec 2017
Jan-09-2018, 10:35 PM
(This post was last modified: Jan-09-2018, 10:35 PM by mpd.)
def __init__(self, first, last):
self._first = first
self._last = last
self.e = self._f + self._l +'@gmail.com' the first time self._f and self._l are used, they are being read. But they have never been defined so you get an Attributeerror
If you remove the last line from the __init__ method, it should work.
|