[Python-Dev] Breaking calls to object.__init__/__new__

Guido van Rossum guido at python.org
Thu Mar 22 04:37:34 CET 2007


On 3/21/07, Jean-Paul Calderone <exarkun at divmod.com> wrote:
> On Wed, 21 Mar 2007 15:45:16 -0700, Guido van Rossum <guido at python.org> wrote:
> >See python.org/sf/1683368. I'd like to invite opinions on whether it's
> >worth breaking an unknown amount of user code in 2.6 for the sake of
> >stricter argument checking for object.__init__ and object.__new__. I
> >think it probably isn't; but the strict version could be added to 3.0
> >and a warning issued in 2.6 in -Wpy3k mode. Alternatively, we could
> >introduce the stricter code in 2.6, fix the stdlib modules that it
> >breaks, and hope for the best. Opinions?
> >
>
> Perhaps I misunderstand the patch, but it would appear to break not just
> some inadvisable uses of super(), but an actual core feature of super().
> Maybe someone can set me right.  Is this correct?
>
>   class Base(object):
>       def __init__(self, important):
>           # Don't upcall with `important` because object is the base
>           # class and its __init__ doesn't care (or won't accept) it
>           super(Base, self).__init__()
>           self.a = important
>
> If so, what are the implications for this?
>
>   class Other(object):
>       def __init__(self, important):
>           # Don't upcall with `important` because object is the base
>           # class and its __init__ doesn't care (or won't accept) it
>           super(Other, self).__init__()
>           self.b = important
>
>   class Derived(Base, Other):
>       pass
>
>
> (A similar example could be given where Base and Other take differently
> named arguments with nothing to do with each other.  The end result is
> the same either way, I think.)
>
> I think I understand the desire to pull keyword arguments out at each
> step of the upcalling process, but I don't see how it can work, since
> "up" calling isn't always what's going on - given a diamond, there's
> arbitrary side-calling, so for cooperation to work every method has to
> pass on every argument, so object.__init__ has to take arbitrary args,
> since no one knows when their "up" call will actually hit object.
>
> Since without diamonds, naive "by-name" upcalling works, I assume that
> super() is actually intended to be used with diamonds, so this seems
> relevant.
>
> I hope I've just overlooked something.  Writing this email feels very
> strange.
>
> Jean-Paul

There are different philosophies about the correct style for
cooperative super calls.

The submitter of the bug report likes to remove "consumed" arguments
and pass the others on, having something at the root that complains
about any unused arguments. It has the problem that you mention: if
multiple classes might be interested in the *same* argument they won't
see it. The other style is to pass *all* arguments down, and let
everyone cherry-pick them. The last call then just throws them away.
This has the problem that misspelled arguments are silently ignored
rather than being diagnosed at the point where you can do something
about it.

I don't know what the "best practice" is (like Greg Ewing, I don't use
either style myself) but I've got a feeling that it must be easier to
solve the former problem than the latter (also I don't know that the
former actually occurs in practice). When using more traditional
styles, or single inheritance, it certainly makes more sense to reject
excess arguments than to ignore them; the original code was clearly
intending to do this, but due to the minimalist coding, it didn't
catch enough.

I've pretty much made up my mind at this point that the right way
forward is to be strict; in 3.0 we can afford to be strict as in the
strict version of the patch, while in 2.6 we'll be less strict, but
still stricter than 2.5; 2.6 in -Wpy3k mode will issue warnings for
those cases where 3.0 will issue an error but 2.6 doesn't.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-Dev mailing list