On 3/21/07, Adam Olsen <[EMAIL PROTECTED]> wrote:
> On 3/21/07, Jean-Paul Calderone <[EMAIL PROTECTED]> wrote:
> > On Wed, 21 Mar 2007 15:45:16 -0700, Guido van Rossum <[EMAIL PROTECTED]> 
> > 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.)
>
> The common name is actually critical.  Your argument names are
> essentially a shared namespace, just like that on the object itself,
> and they're both modifying it on the assumption of being the only
> thing that does so.
>
> There's two ways to fix your example.  First, adding a common base
> class which is the "owner" of that name:
>
> class Owner(object):
>     def __init__(self, important, **kwargs):
>         super(Owner, self).__init__(**kwargs)  # important is skipped
>
> class Left(Owner):
>     def __init__(self, important, **kwargs):
>         super(Left, self).__init__(important=important, **kwargs)
>
> class Right(Owner):
>     def __init__(self, important, **kwargs):
>         super(Right, self).__init__(important=important, **kwargs)
>
> class Derived(Left, Right):
>     pass
>
> >>> Derived("hi")
>
>
> The other is to rename the argument, removing the namespace conflict:
>
> class Left(object):
>     def __init__(self, oranges, **kwargs):
>         super(Left, self).__init__(oranges=oranges, **kwargs)
>
> class Right(object):
>     def __init__(self, apples, **kwargs):
>         super(Right, self).__init__(apples=apples, **kwargs)
>
> class Derived(Left, Right):
>     pass

Hmm, where's that "undo post" button...

That should be:

class Left(object):
    def __init__(self, oranges, **kwargs):
        super(Left, self).__init__(**kwargs)

class Right(object):
    def __init__(self, apples, **kwargs):
        super(Right, self).__init__(**kwargs)

class Derived(Left, Right):
    pass

And I would have gotten an error when I tested it had I been using the
strict __init__.

>
> >>> Derived(apples=3, oranges=8)
>
> In this second version you could clean up Derived's interface by
> adding either "def __init__(self, apples, oranges, **kwargs)" and
> passing them both explicitly, or by adding "def __init__(self, *,
> **kwargs)" and requiring they by given to you by name.  Either way
> you're completely safe.
>
>
> >
> > 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.
>
> super() has always felt strange to me.  Now, with PEP 3102 and the
> strict __init__, not so much.
>
> --
> Adam Olsen, aka Rhamphoryncus
>


-- 
Adam Olsen, aka Rhamphoryncus
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to