is python Object oriented??
Steven D'Aprano
steven at REMOVE.THIS.cybersource.com.au
Tue Feb 3 19:51:46 EST 2009
On Tue, 03 Feb 2009 10:20:28 +0100, Thorsten Kampe wrote:
>> If a "private" keyword (or equivalent) were available, then the change
>> would need to be made in only one location rather than at every
>> occurrence off the identifier. That is much less error prone. Sure, you
>> can argue (as I'm sure someone will) that the users of the library
>> should be more careful. Yes they should, but why not let the language
>> help with such low-level details. That's what high-level languages are
>> for.
>
> This scenario is highly "supposing" and doesn't look like a real-world-
> case to me.
You think that private attributes never become public?
Encoding a "private" flag in the name is a violation of Once And Only
Once. Although the OAOO principle is generally referred to when
discussing code, it is more generic and applies to other things as well.
You should be able to state an attribute is private *once*, not every
time you use it.
http://c2.com/cgi/wiki?OnceAndOnlyOnce
On the other hand, encoding that private flag in the name is a variation
of *sensible* Hungarian Notation, as used by the Microsoft Apps team, not
the stupid version used by the Windows team.
http://www.joelonsoftware.com/articles/Wrong.html
So that's a point in its favour.
> But anyway: the obvious solution in my humble opinion would
> be to do something like "public_attribute = _private_attribute". But
> that would be too simple, too "unjavaesque", right?!
No, it would be too *faulty*. It simply doesn't work. Consider:
class Parrot(object):
_count = 0
def foo(self):
print 'foo'
self._count += 1
def bar(self):
print "You have called foo %d times" % self._count
This works as expected:
>>> p = Parrot()
>>> p.foo()
foo
>>> p.foo()
foo
>>> p.bar()
You have called foo 2 times
Now you promote count from private to public, using your "obvious
solution", and try to use it:
class Parrot(object):
_count = 0
count = _count
def foo(self):
print 'foo'
self._count += 1
def bar(self):
print "You have called foo %d times" % self._count
>>> p = Parrot()
>>> p.foo()
foo
>>> p.count = 99
>>> p.bar()
You have called foo 1 times
Clearly the "obvious" solution simply isn't sufficient to get the result
that you need. One solution is to just refactor the source code, so that
the attribute identifier "_count" becomes "count", but beware of all the
usual issues with source code refactoring.
Another solution is to leave _count as it is, and create a *property*
called count, not a simple attribute:
count = property(
lambda self: self._count,
lambda self, x: setattr(self, '_count', x),
None,
"Public interface to private attribute _count"
)
but this adds complexity to the class and will be a maintenance headache
as the class' methods diverge into those that manipulate self._count
directly and other methods which manipulate self.count.
--
Steven
More information about the Python-list
mailing list