[Tutor] Class Construction question [C++ and Python class
introduction]
Magnus Lycka
magnus@thinkware.se
Wed Nov 13 08:28:01 2002
At 22:41 2002-11-12 -0800, Danny Yoo wrote:
>Also, unlike C++, there's just one "namespace" for both methods and
>attributes. There's a unity to this approach, a uniform way of getting at
>both methods and "regular" attribute values:
Ouch! I had forgotten that you can do such bizarre things
in C++ as to give the same name to an attribute and a
method. Yuk. I'm so happy I can program Python all day long
now... :) (I try to give my method name verb names anyway...)
>So by convention, we often put a single understore in front of our
>attribute names. It sounds a bit informal, but it works pretty well!
>
>###
> >>> class Book:
>... def __init__(self, title):
>... self._title = title
>... def title(self):
>... return self._title
>...
> >>> b = Book("generatingfunctionology")
> >>> b.title()
>'generatingfunctionology'
>###
To continue the parallels with C++, It's common that people use
self.x to denote a public attribute,
self._x to denote a protected and
self.__x to denote a private attribute
(I think it might be good if there was more of a complete
consensus about this, but on the other hand, there are some
concerns about the validity of this three step protection
anyway. I even think that I read that Bjarne himself felt
that it was too much to have these three levels...)
self._x or self._title etc are not protected by the programming
language. It's up to the programmers and perhaps reviewers to
assert that this "protection" isn't abused. It's a bit like putting
a "don't disturb" sign on the door instead of locking it, and it
usually works well. If programmers can't follow such a convention,
they won't be able to follow other project guidelines such as
coding style guides or naming conventions either. (Or functional
requirements?)
Using double initial underscores: self.__x *is* handled in a special
way by Python:
>>> class X:
... def __init__(self, private):
... self.__private = private
... def __str__(self):
... return str(self.__private)
...
>>> x = X('secret')
>>> print x
secret
>>> print x.__private
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
AttributeError: X instance has no attribute '__private'
>>> print x.__dict__
{'_X__private': 'secret'}
>>> #Aha!
>>> print x._X__private
secret
The attributes with double underscores can be used normally
inside the class (as in the __str__ method which is implicitly
used in "print x") but externally, the attribute name is changed.
This means that there is no way you can abuse private variables
unintentionally. You CAN if you need to though. This is helpful
in debugging, etc.
Don't ever *end* private with __ though. You don't want to confuse
__private__ with __magic__ as __str__, __init__ etc.
It's often claimed that all attributes should be at least protected,
and only accessed through set or get methods. With this assumption,
it's obviously logical to do as Danny wrote above.
In Python this isn't really such a big issue though, because of
the magic methods __setattr__ and __getattr__. They can override
attribute modification and access. This means that if you change
your mind, and for instance calculate a value on the fly instead
of storing it, you can handle that change even if there is code
that assumes it can read this value as an attribute. See below:
>>> class Sum:
... def __init__(self, a, b):
... self.sum = a + b
...
>>> x = Sum(1,2)
>>> x.sum
3
>>> x.smu
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
AttributeError: Sum instance has no attribute 'smu'
>>> class Sum:
... def __init__(self, a, b):
... self.__a = a
... self.__b = b
... def __getattr__(self, name):
... if name == 'sum':
... return self.__a + self.__b
... else:
... raise AttributeError, "Sum instance has no
attribute '%s'" % name
...
>>> x = Sum(1,2)
>>> x.sum
3
>>> x.smu
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
File "<interactive input>", line 9, in __getattr__
AttributeError: Sum instance has no attribute 'smu'
Voila!
--
Magnus Lycka, Thinkware AB
Alvans vag 99, SE-907 50 UMEA, SWEDEN
phone: int+46 70 582 80 65, fax: int+46 70 612 80 65
http://www.thinkware.se/ mailto:magnus@thinkware.se