[Python-checkins] r54539 - in python/trunk: Lib/string.py Misc/NEWS Objects/typeobject.c

Jim Jewett jimjjewett at gmail.com
Fri Mar 23 20:55:50 CET 2007


On 3/23/07, Guido van Rossum <guido at python.org> wrote:
> On 3/23/07, Jim Jewett <jimjjewett at gmail.com> wrote:
> > (Please note that most replies should trim at least one list from the Cc)
>
> [-dev, -ideas]
>
> > On 3/23/07, guido.van.rossum <python-checkins at python.org> wrote:
> > > Note: without the change to string.py, lots of spurious warnings happen.
> > > What's going on there?
> >
> > I assume it was a defensive measure for subclasses of both Template
> > and X, where X has its own metaclass (which might have an __init__
> > that shouldn't be ignored).
> >
> > This is where cooperative classes get ugly.  You could argue that the
> > "correct" code is to not bother making the super call if it would go
> > all the way to object (or even type), but there isn't a good way to
> > spell that.
>
> *Correct* code knows whether it is defining or extending a method, so
> it always knows whether to call the super method or not.

class Window:
    def close():  # No supertype but object

class DBConnection:
    def close():  # No supertype but object

class DBView(DBConnection, Window):
    ???


DBConnection is defining close.  There is no super.close on most
instances.  So it can't call close blindly.

But if it doesn't call super.close, then DBView has to call both
superclasses by name -- and there isn't much point to super.

One workaround is to make both Window and DBConnection subclasses of
(Abstract Base Class/Interface) LimitedResource.
LimitedResource.close wouldn't do anything, but it would know not to
pass the call on any farther.  This is arguably the most correct, but
perhaps the worst in practice.  You lose duck-typing, you need to
agree on a framework, and you get lots of extra do-nothing function
calls.


> > > +        # A super call makes no sense since type() doesn't define __init__().
> > > +        # (Or does it? And should type.__init__() accept three args?)
> > > +        # super(_TemplateMetaclass, cls).__init__(name, bases, dct)

> > In this particular case, you could define a type.__init__ that did
> > nothing.  (If the signature were wrong, type.__new__ would have
> > already caught it.  If __new__ and __init__ are seeing something
> > different, then the change was probably intentional.)

> No, super calls to __init__ may see different arguments than __new__.

Yeah, but only if the arguments to at least one of them are
intentionally modified.

> I'm adding a type_init() that insists on the minimal (default)
> signature and calls object.__init__() with no args (just in case
> object.__init__() ever grows useful functionality :-).

And you get the same "that would be annoying" problem you were trying to avoid.

    class MyMeta(type):
        def __new__(cls, name, bases, dict, myflags):
            ...
            return super(MyMeta, cls).__new__(name, bases, dict)
        def __init__(cls, name, bases, dict, myflags):
            """Do-nothing junk function to shut up type.__init__.

                Warning:  This will still fail if there are any other
metaclasses that
                wanted their own special argument like myflags..."""
            return super(MyMeta, cls).__init__(name, bases, dict)

> > The problem isn't really limited to type.__init__ though.  You'll
> > sometimes see similar patterns for __del__, close, save, etc.

> Again, it seems to be caused by confusion about whether one is
> defining or extending the method. This is probably not clearly
> documented for __del__(), but the intention was that object does *not*
> define __del__().

The example abouve makes just as much sense with __del__.  Most
__del__ methods boil down to self.close().

> For close() and save() I would venture it is
> definitely a bug in the application if they don't know whether they
> are defining or extending it.

With single-inheritance, yes.
For a (java) final class, yes.

For a class that might be on one branch of multiple inheritance, it
depends on the instance.


> > The
> > main difference is that they have to either catch an error or check
> > first, since object doesn't have an implementation of those methods.
> > object.__init__ doesn't really do anything either, except check for
> > errors.  Getting rid of it should have the same effect as complaining
> > about parameters.

> Getting rid of what?

Getting rid of object.__init__.

    >>> object(1,2,3)

    Traceback (most recent call last):
      File "<pyshell#14>", line 1, in <module>
        object(1,2,3)
    TypeError: default __new__ takes no parameters
    >>> object.asdf(1,2,3)

isn't all that much better than what you get for a missing method

    >>> object(1,2,3)

    Traceback (most recent call last):
      File "<pyshell#15>", line 1, in <module>
        object(1,2,3)
    AttributeError: type object 'object' has no attribute '__init__'

-jJ


More information about the Python-checkins mailing list