OO in Python (was Re: Migrating to perl?)

Alex Martelli aleaxit at yahoo.com
Fri Jan 5 07:59:57 EST 2001


"Joel Ricker" <joejava at dragonat.net> wrote in message
news:ggd56.4652$of7.222552 at news1.atl...
    [snip]
> From your examples, Pythons class model is much cleaner.  Also if I
> understand your example, variables internal to the object are kept
> internal -- they can't be accessed without a proper method.  With perl

You can arrange things as to avoid *accidental* direct accesses to
object-instance attributes, but client-code is still able to get
around your precautions and reach the 'real' attributes if it so
wishes.  That's why the emphasis on avoiding *accidents* -- this
is not a *security* mechanism, in Python.

Python relies *a lot* on code respecting certain conventions, as
opposed to *enforcing* them (in this, it's much like C++ -- although
the latter has a LOT more apparently-enforcing mechanisms, and thus
complexity, some 'casts' in the client-code can break all the apparent
'protection'... so you end up relying on conventional good-behavior
anyway, in the end; Java is different -- it does [try to] use its
access-protection to enforce security, rather than just to ward
against accidents).

If you do need enforcement, because you're getting Python code to
execute from a source you don't trust, you can go to a model of
'restricted execution', "Bastions", and so on, but that's more
complex; you only do it when you truly need it, which is NOT often.

"Do the simplest thing that can possibly work" is a good principle
(the first and foremost one in the "Extreme Programming" school,
or sect:-).  Very often, you don't mind if client code accesses
object-instance attributes freely -- the 'simplest thing' is then
to not worry about it.  You'll be surprised at how often this
works just fine, with no hassles on anybody.

Given that most needs are met by wise non-action, as above, all
of the following is somewhat "advanced"... you may be able to
write LOTS of excellent Python code without needing ANY of the
following -- very simply, and very productively, too.


Sometimes, your object-instance needs to monitor any _modification_
to its attributes, to ensure its overall state remains 'correct'
(meets the 'class invariant' you have designed).  This need is not
all that rare.  Python meets it by letting you define __setattr__:
every attempt to bind or rebind an attribute of your instance
*directly* (e.g., with the normal syntax 'inst.attrib=value') will
cause __setattr__ to be called, and it can do any monitoring needed
(forbid the modification, apply other modifications so that the
overall state stays consistent, invalidate internal caches, etc).

[But client code CAN still get at the 'dictionary' where your
instance stores its attribute name->value mapping, and do changes
*without* __setattr__ being triggered: that's not something that's
going to happen "by accident", of course!  But, again, this is
NOT a viable _security_ mechanism against untrusted client-code].


A somewhat rarer need is to 'compute' some attributes "on the
fly", or, as is also said, "lazily" -- only if, and, when the
attribute values are needed.  *This* need is met by Python's
letting you define __getattr__, which gets called any time an
access is attempted (e.g., via the normal syntax 'foo=inst.attr')
*to an attribute that is NOT in the dict*.


You can meet even-rarer needs (requiring __getattr__ to be
called anyway) by deliberately *not* keeping in the dict the
attributes that client code will access -- you can stash them
(or whatever state you need to recompute them) somewhere else,
or you can still keep them (or etc) as attributes, but under
some assumed name.  One approach to the latter is to name the
'real' attributes with two leading underscores (but _not_ two
_trailing_ underscores as well): in this case, Python will
insert the classname in the attribute name, so that if a
method of class 'Foop' accesses attribute '__peep' in one of
its instances, the real name accessed will be _Foop__peep --
this basically ensures against any accidental clash (sorry
to be repetitive, but -- again, this is NOT 'security'...).

This 'two leading underscores' naming is how you do "private"
attributes in Python, whether it be for __getattr__ purposes
or just to let a class instance keep some state that client
code is not supposed to access at all (except, presumably,
indirectly through its influence on instance behavior). (The
latter is actually a pretty rare *need* -- it only happens
with substantial frequency because people's designs are
influenced by their experience with other OO languages).


> anything goes.  There are some techniques to prevent this but it isn't
> definite.  Its actually this very topic that made me throw my new OO book
> across the room and subscribed to this newsgroup :)

Perl's object model was inspired by Python's (according to
Srinivasan's "Advanced Perl Programming"), but it's less
smoothly integrated with the language since it came to Perl
pretty late in that language's history (in the Perl 4 -> Perl
5 transition).


> I've mentioned before that I'm real new to OO.  How should I approach it
in
> Python?  Has anyone learned OO just from Python?

Yes -- it's not a common occurrence yet, I believe, but it's
what happening to my son, for example... his previous experiences
were with Pascal and machine-language, no OO in sight, and now
he's starting to use Python, so that's the context in which he's
first meeting OO concepts.

> Or should I study OO
> theory else where and then apply it to Python?  I know this is bordering
on
> the question of how do I do OO but I really know very little about it...
> enough to know that I can benefit from it and basic ideas.  I understand
the
> idea of a class and building objects from it but anything beyond that is
> still really new to me.  Any suggestions?

I don't think there is a really good "OO theory" text that does
not make some reasonably strong assumptions on the object model
that will be in use -- which, in turn, means the language that
will be in use.  If you learn OO based on an object model that
(e.g.) assumes compile-time static typing, or single inheritance,
etc, that will not make your transition to Python OO all that
smooth or easy (quite feasible, of course -- the more languages
you know and understand, the easier it is to learn any N+1-th
language, and Python IS quite easy in any event).

I suspect that the most productive path, given the current OO
literature, might be simply for you to "feel your way".  If you're
inclined to think "in diagrams", maybe some good introductory UML
text might help (but I can't suggest one -- I think in strongly
_textual_ ways, so all the diagrams confuse me more than they
help me... I suspect I'm pretty unusual in this respect).


Alex






More information about the Python-list mailing list