Python Forum
Private instance variables
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Private instance variables
#1
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.
Reply
#2
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.
Reply
#3
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.
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#4
(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.
Reply
#5
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...
Reply
#6
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.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020