Re: myfile.py: a Class wrapper for file objects & prompting readlines()

Guido.van.Rossum@cwi.nl
Wed, 02 Mar 1994 10:52:16 +0100

> Note: a while ago, I recall some discussion of how to structure
> __init__()'s in a class hierarchy. I guess I wasn't paying
> attention at the time. :-)
>
> class NumPromptFile( SimplePromptFile, File )
> was originally
> class NumPromptFile( SimplePromptFile )
> but
> apply ( self.__class__.__bases__[-1].__init__, (self,)+args )
> caused an infinite recursion.
>
> This may be obvious to some of you, but I misunderstood what would be
> in self.__class__.__bases__ : I thought that it would have ALL of the
> ancestors, but it only contains the ancestors mentioned in the class
> inheritance list. To allow some scheme of chaining __init__'s, Either
> the base superclass must be put in explicitly ( the current kludge )
> or we need a function to return the entire inheritance tree
> (partially flattened ? )

Ooohh, Steve! The line

> apply ( self.__class__.__bases__[-1].__init__, (self,)+args )

just hurts my eyes. Classes are *designed* to have a static
inheritance pattern. It is not a sin to repeat the name of the base
class explicitly when extending a method of the base class -- quite to
the contrary, this is recommended practice!

What you do will major screw up any class derived from
SimplePromptFile. The expression "self.__class__" is by definition
the most derived class, *not* the class containing the line.
Therefore self.__class__.__bases__[-1] can be *anything*...

I strongly recommend to rewrite

> class SimplePromptFile( File ):
> def __init__( self, *args ):
> # the next line caused some troubles in the next class!!! (*note A)
> apply ( self.__class__.__bases__[-1].__init__, (self,)+args )

as

! class SimplePromptFile( File ):
! def __init__( self, *args ):
! apply(File.__init__, (self,)+args )

Another thing that makes my body cringe in pain is the call to
self.__init__() in your open() method, although for a less fundamental
reason: what you really want is a reset() (or _reset()) method which
is called both by __init__() and open().

Finally: don't be mislead into thinking that there's anything special
about extending __init__() -- the same rule ("it's Good to mention the
base class explicitly") holds for extending any other method! It's
just because extending __init__() is more common that you associate
this whole mess with __init__()...

Here's an exercise: practice programming for a while without using
self.__class__, self.__dict__, or <class>.__bases__. Come to think of
it, __main__ and __name__ are also out, *except* to differentiate
between a script and an imported module. All these attributes are
there mostly for debuggers and other tools, not to pervert Python into
Scheme!

(I wonder if I should've made a distinction between these and, say,
__init__ and __del__ which are perfectly legal to use...)

--Guido van Rossum, CWI, Amsterdam <Guido.van.Rossum@cwi.nl>
URL: <http://www.cwi.nl/cwi/people/Guido.van.Rossum.html>