Deprecate self

Alex Martelli aleaxit at yahoo.com
Wed Apr 18 17:03:53 EDT 2001


"Rainer Deyke" <root at rainerdeyke.com> wrote in message
news:OLlD6.46125$J%5.15304817 at news2.rdc2.tx.home.com...
    [snip]
> > Aha, here's where you see the inconsistency.  The analogy is just
> > not there.  A method may be called on objects that are not in its
    [snip]
> The analogy is not universally applicable, but it is most certainly
"there".

About at the same level as that between ravens and writing desks
(I'm sure you are familiar with Carroll's works, right?).  At a sufficiently
weak level, you can analogize everything and anything.  That doesn't
mean it makes any _sense_ to do so, of course.

> Consider singletons (i.e. classes which by design only have a single
> instance and no subclasses).

How do you stop a class from having subclasses in Python?  (And
what is the supposed benefit of that -- assuming you can find any
benefits for the singleton DP anywhere, of course).

> Or consider random number generators.  The
> documentation specifies an interface for random number generators which I
> can implement through a module (like module 'random').  If I later decide
I
> need more than one instance of my random number generator with seperate
> state, I can move the functions of that module into a class and use
intances
> of that class to generate random numbers.  This requires that I add 'self'
> as first argument to all functions and 'self.' before all state accesses:
a
> tedious and error-prone process.

Finally, a point.  Yes, a very deep refactoring such as changing a module
into a class, since they're very different things, will require many
changes.

Among them, besides the ones you note, will probably be the introduction
of inheritance to capture code commonality and a lot of decision to make
about what state is per-class and what is per-instance (not to mention
similar decisions about callables).

The task of helping with such refactoring chores, of course, is properly
one for editing-time tools; it would be pretty foolish to distort a language
to make it easier to do with a dumb editor part of what one should really
be using a refactoring-browser or similar tool to accomplish.


> > The module is, basically, just a namespace.
>
> So is a class.  So is a class instance.

Except (for example) that classes have inheritance, while modules do
not, and instances have rich lookup instance->class->bases, while,
again, modules do not.  So a class or instance is in fact NOT just a
namespace but a _structured_ one.

> class colors:
>   red = 0
>   green = 1
>   blue = 3
>
> class EmptyClass: pass
> state = EmptyClass()
> state.frame = 0

And x=colors(); x.red=22, whereupon you get the instance dictionary
"overriding" (so to speak) the class one on any getattr.  Not JUST a
namespace, see?  Which is why 'self' is needed as an argument to
methods, and access that go through it are so different from ones
that don't.


> >  A function, _and_ btw
> > a method too, can access that namespace implicitly or explicitly
> > [eg via globals()].  It would make no sense for it to be an argument
> > to the function since it doesn't change at each call -- while the

I note you have signally failed to address this horrid defect in the
analogy you claim "is there".  A method has a global namespace
_as well_ as access to self as an argument.  If functions were to
access their global namespace though some magic overloading of
self, how WOULD methods access THEIR global namespace?


> > instance on which a method is being called CAN definitely differ
> > at each call.
> >
> > > However, this does not work if 'f' takes a variable number of argument
> > (and
> > > is tedious besides).  In C++, I can explicitly qualify global
variables:
> >
> > So you can in Python, if you wish -- globals() lets you do that
> > most easily.
>
> 'globals()' is syntactically awkward and semantically different from
> attribute access.

Yes, for special attributes.  Just as in C++ namespace qualification is
syntactically and semantically different from attribute access, too, save
that the Python situation is simpler.  As you chose to assert this is done
right in C++, you're being inconsistent in bemoaning "similar
differences" (interesting pseudo-oxymoron here:-) in Python.


> # Module spam.py
> import spam
> print spam.__dict__
> print globals()['__dict__']
>
> A module importing itself is still the best idiom here.

Your choice.  I prefer globals(), myself.


> > > namespace jam {
> > >   int x = 5;
> > >   void f()
> > >   {
> > >     std::cout << ::jam::x << std::endl;
> > >   }
> > > }
> > >
> > > Another thing that C++ got right and Python got wrong.
> >
> > The intricacies of C++ scoping can hardly be taken as an example
> > of things "C++ got right".
>
> I'm not talking about the intricacies of C++ scoping, but this very
specific
> case.

A case that will crash and burn as soon as this gets wrapped into
another namespace (as will no doubt have to happen soon, since
first thing you know code will have to use this AND another silly
library using a similarly uninspired namespace name)...? Please.

This use of namespaces is NOT good C++ style.  Sure, you can
do it -- and get away with it as long as you're playing with toy
sized systems, maybe.  In real large-scale C++ software, though,
you had better stick to canonic use.  Please see Meyers' Effective
C++, CDROM edition, for the most elementary and fundamental
basics.  Koenig and Moo in "Ruminations on C++" have quite
usable material, too.  To make a long story short, namespaces
ARE meant for large-scale software and the top-level namespaces
had better be unique.  You'll use using-declarations to make such
long unique namespaces usable.


> > Python's scoping is crystal-simple (up to 2.1 excluded -- I have
> > not yet delved into the new lexical scoping things deep enough
> > to underwrite their simplicity, although one does hope from PEP
> > reading & such things:-).
>
> Lack of lexical scoping is another thing Python got wrong.  It causes code
> not to work when moved from one scope to another.  However, I had not
> intended to start a general discussion of scoping in programming
languages.

Yet that's what you did -- because (while making no actual usable
proposals) you started bemoaning the use of self in methods and/or
its non-use in module-level functions.  These ARE scoping issues,
after all.  Could you really not be aware of that fact?


> > In other words, my dislike for C++'s complexities is NOT due
> > to insufficient familiarity with them -- indeed, maybe the
> > reverse, since I spend so much of my time and energy in
> > clarifying the finer points of several combinations of very
> > obscure provisions & implementations' bugs to highly skilled
> > software development professionals that keep getting badly
> > burned by all of the tripwires (I insist that you HAVE to
> > mix metaphors A LOT to get into the spirit of C++...:-).
>
> I understand very much the value of simplicity and the horror of C++'s
> complexity.  I see inconsitency and over-specialized syntax as the primary
> causes, so I attack them in language design whereever I find it - even in
> mostly sane languages like Python.

What would the "over-specialized syntax" you are attacking be
in this case?  Please be specific.  I see nothing over-specialized
in a method or function receiving an object and accessing its
attributes with dot syntax, while both access global names
without such qualification:

x = 23

def afun(obj):
    print x
    print obj.x

class Aclass:
    x = 45
    def amet(self):
        print x
        print self.x

The "print x" refers to the global module x in each case, while
the Z.x for some Z (which happens to be the first argument in
each case) refers to attribute x of object Z.  Total consistency
(indeed, identity) and no specialized syntax whatsoever.  So,
are you seeing ghosts?


Alex






More information about the Python-list mailing list