Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #56500 > unrolled thread

super in Python 3 and variadic arguments

Started byMarco Buttu <marco.buttu@gmail.com>
First post2013-10-09 17:44 +0200
Last post2013-10-11 08:15 +0200
Articles 11 — 5 participants

Back to article view | Back to comp.lang.python


Contents

  super in Python 3 and variadic arguments Marco Buttu <marco.buttu@gmail.com> - 2013-10-09 17:44 +0200
    Re: super in Python 3 and variadic arguments Ned Batchelder <ned@nedbatchelder.com> - 2013-10-09 12:47 -0400
      Re: super in Python 3 and variadic arguments Marco Buttu <marco.buttu@gmail.com> - 2013-10-10 09:22 +0200
        Re: super in Python 3 and variadic arguments Ned Batchelder <ned@nedbatchelder.com> - 2013-10-10 07:04 -0400
          Re: super in Python 3 and variadic arguments Marco Buttu <marco.buttu@gmail.com> - 2013-10-10 14:54 +0200
          Re: super in Python 3 and variadic arguments Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-10-11 02:11 +0000
            Re: super in Python 3 and variadic arguments Ian Kelly <ian.g.kelly@gmail.com> - 2013-10-10 20:33 -0600
              Re: super in Python 3 and variadic arguments Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-10-11 03:00 +0000
                Re: super in Python 3 and variadic arguments Chris Angelico <rosuav@gmail.com> - 2013-10-11 17:08 +1100
              Re: super in Python 3 and variadic arguments Marco Buttu <marco.buttu@gmail.com> - 2013-10-11 08:17 +0200
            Re: super in Python 3 and variadic arguments Marco Buttu <marco.buttu@gmail.com> - 2013-10-11 08:15 +0200

#56500 — super in Python 3 and variadic arguments

FromMarco Buttu <marco.buttu@gmail.com>
Date2013-10-09 17:44 +0200
Subjectsuper in Python 3 and variadic arguments
Message-ID<l33tlf$rr1$1@speranza.aioe.org>
Given this class:

 >>> class A:
...     def afoo(*args):
...         print(args)

in Python 3 we can write the following class:

 >>> class B(A):
...     def bfoo(*args):
...         super(B, args[0]).afoo(*args[1:])
...
 >>> B().bfoo(1, 2, 3)
(<__main__.B object at 0x7f5b3bde48d0>, 1, 2, 3)


without giving arguments to super, in this way:

 >>> class B(A):
...     def bfoo(self, *args):
...         super().afoo(*args)
...
 >>> B().bfoo(1, 2, 3)
(<__main__.B object at 0x7f5b3bdea0d0>, 1, 2, 3)

But it does not work in this case:

 >>> class B(A):
...     def bfoo(*args):
...         super().afoo(*args[1:])
...
 >>> B().bfoo(1, 2, 3)
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "<stdin>", line 3, in bfoo
RuntimeError: super(): no arguments

How come?
-- 
Marco Buttu

[toc] | [next] | [standalone]


#56504

FromNed Batchelder <ned@nedbatchelder.com>
Date2013-10-09 12:47 -0400
Message-ID<mailman.902.1381337680.18130.python-list@python.org>
In reply to#56500
On 10/9/13 11:44 AM, Marco Buttu wrote:
> Given this class:
>
> >>> class A:
> ...     def afoo(*args):
> ...         print(args)
>
> in Python 3 we can write the following class:
>
> >>> class B(A):
> ...     def bfoo(*args):
> ...         super(B, args[0]).afoo(*args[1:])
> ...
> >>> B().bfoo(1, 2, 3)
> (<__main__.B object at 0x7f5b3bde48d0>, 1, 2, 3)
>
>
> without giving arguments to super, in this way:
>
> >>> class B(A):
> ...     def bfoo(self, *args):
> ...         super().afoo(*args)
> ...
> >>> B().bfoo(1, 2, 3)
> (<__main__.B object at 0x7f5b3bdea0d0>, 1, 2, 3)
>
> But it does not work in this case:
>
> >>> class B(A):
> ...     def bfoo(*args):
> ...         super().afoo(*args[1:])
> ...
> >>> B().bfoo(1, 2, 3)
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "<stdin>", line 3, in bfoo
> RuntimeError: super(): no arguments
>
> How come?

The no-args super() call inspects the calling environment to determine 
the class and self.  "self" is the first local name stored in 
frame.f_code.co_localsplus, but *args doesn't put "args" into that entry 
of the code object.  Basically, super() is looking for the first regular 
argument in the function.

--Ned.

[toc] | [prev] | [next] | [standalone]


#56552

FromMarco Buttu <marco.buttu@gmail.com>
Date2013-10-10 09:22 +0200
Message-ID<52565598.6000709@gmail.com>
In reply to#56504
On 10/09/2013 06:47 PM, Ned Batchelder wrote:

>> >>> class B(A):
>> ...     def bfoo(*args):
>> ...         super().afoo(*args[1:])
>> ...
>> >>> B().bfoo(1, 2, 3)
>> Traceback (most recent call last):
>>   File "<stdin>", line 1, in <module>
>>   File "<stdin>", line 3, in bfoo
>> RuntimeError: super(): no arguments
>>
>> How come?
>
> The no-args super() call inspects the calling environment to determine
> the class and self.  "self" is the first local name stored in
> frame.f_code.co_localsplus, but *args doesn't put "args" into that entry
> of the code object

But is it a bug or the behavior we want? The first (implicit) argument 
is stored as expected as the first one in the args tuple, and the args 
tuple is inserted as expected in frame.f_locals:

 >>> import inspect
 >>> class B(A):
...     def bfoo(*args):
...         frame = inspect.currentframe()
...         for obj, value in frame.f_locals.items():
...             print(obj, value, sep=' --> ')
...         # super().afoo(*args[1:])
...
 >>> B().bfoo(1, 2, 3)
args --> (<__main__.B object at 0x7f28c960a590>, 1, 2, 3)
frame --> <frame object at 0x7f28cad4b240>

So, why does not super use it?

-- 
Marco Buttu

[toc] | [prev] | [next] | [standalone]


#56558

FromNed Batchelder <ned@nedbatchelder.com>
Date2013-10-10 07:04 -0400
Message-ID<mailman.932.1381403081.18130.python-list@python.org>
In reply to#56552
On 10/10/13 3:22 AM, Marco Buttu wrote:
> On 10/09/2013 06:47 PM, Ned Batchelder wrote:
>
>>> >>> class B(A):
>>> ...     def bfoo(*args):
>>> ...         super().afoo(*args[1:])
>>> ...
>>> >>> B().bfoo(1, 2, 3)
>>> Traceback (most recent call last):
>>>   File "<stdin>", line 1, in <module>
>>>   File "<stdin>", line 3, in bfoo
>>> RuntimeError: super(): no arguments
>>>
>>> How come?
>>
>> The no-args super() call inspects the calling environment to determine
>> the class and self.  "self" is the first local name stored in
>> frame.f_code.co_localsplus, but *args doesn't put "args" into that entry
>> of the code object
>
> But is it a bug or the behavior we want? The first (implicit) argument 
> is stored as expected as the first one in the args tuple, and the args 
> tuple is inserted as expected in frame.f_locals:
>
> >>> import inspect
> >>> class B(A):
> ...     def bfoo(*args):
> ...         frame = inspect.currentframe()
> ...         for obj, value in frame.f_locals.items():
> ...             print(obj, value, sep=' --> ')
> ...         # super().afoo(*args[1:])
> ...
> >>> B().bfoo(1, 2, 3)
> args --> (<__main__.B object at 0x7f28c960a590>, 1, 2, 3)
> frame --> <frame object at 0x7f28cad4b240>
>
> So, why does not super use it?
>

I haven't seen the discussion that decided the behavior of super(), but 
I'd guess that if you reported this as a bug, it would be closed as 
wontfix, because: 1) the use case you describe isn't something people 
actually write, 2) it would add to the complexity of super() to support 
it, and 3) there's a simple way to write your code that does work:

     class B(A):
         def bfoo(self, *args):
             super().afoo(*args)

(though it's a bit odd to call afoo from bfoo.)

Python has never claimed the kind of purity that makes everything work 
in a totally simple consistent way.  super() with no args is a kind of 
hack to begin with.  It involves a special case in the compiler (so that 
using the name "super" as a function call will act as if you had 
accessed the name "__class__" so that super can find it later), and 
inspecting the stack frame during execution.

It's an interesting case of the Zen of Python.  It violates one 
("explicit is better than implicit"), but only because of another one 
("practicality beats purity").  super(MyClass, self) in Python 2 is the 
kind of brain-bender that so many people get wrong at first, that it's 
helped plenty of people to do the arguments implicitly, even if there 
are oddball edge cases that it doesn't seem to handle properly.

--Ned.

[toc] | [prev] | [next] | [standalone]


#56563

FromMarco Buttu <marco.buttu@gmail.com>
Date2013-10-10 14:54 +0200
Message-ID<l3681f$gqh$1@speranza.aioe.org>
In reply to#56558
On 10/10/2013 01:04 PM, Ned Batchelder wrote:

> On 10/10/13 3:22 AM, Marco Buttu wrote:
>> >>> import inspect
>> >>> class B(A):
>> ...     def bfoo(*args):
>> ...         frame = inspect.currentframe()
>> ...         for obj, value in frame.f_locals.items():
>> ...             print(obj, value, sep=' --> ')
>> ...         # super().afoo(*args[1:])
>> ...
>> >>> B().bfoo(1, 2, 3)
>> args --> (<__main__.B object at 0x7f28c960a590>, 1, 2, 3)
>> frame --> <frame object at 0x7f28cad4b240>
>>
>> So, why does not super use it?
>>
>
> Python has never claimed the kind of purity that makes everything work
> in a totally simple consistent way.  super() with no args is a kind of
> hack to begin with.  It involves a special case in the compiler (so that
> using the name "super" as a function call will act as if you had
> accessed the name "__class__" so that super can find it later), and
> inspecting the stack frame during execution.

It seems reasonable

> It's an interesting case of the Zen of Python.  It violates one
> ("explicit is better than implicit"), but only because of another one
> ("practicality beats purity").  super(MyClass, self) in Python 2 is the
> kind of brain-bender that so many people get wrong at first, that it's
> helped plenty of people to do the arguments implicitly, even if there
> are oddball edge cases that it doesn't seem to handle properly.
>
> --Ned.

Thanks for the comprehensive answer ;)

-- 
Marco Buttu

[toc] | [prev] | [next] | [standalone]


#56632

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-10-11 02:11 +0000
Message-ID<52575e47$0$29984$c3e8da3$5496439d@news.astraweb.com>
In reply to#56558
On Thu, 10 Oct 2013 07:04:38 -0400, Ned Batchelder wrote:

> super() with no args is a kind of hack to begin with.  It involves a
> special case in the compiler (so that using the name "super" as a
> function call will act as if you had accessed the name "__class__" so
> that super can find it later), and inspecting the stack frame during
> execution.

super() with no arguments is *completely* a hack[1], and one where GvR 
has said "Never again!" if I remember correctly. I don't think he regrets 
allowing the super compile-time magic, just that it really is magic and 
he doesn't want to make a habit of it.

One of the side-effects of this being a hack is that this doesn't work:

class X(Y):
    def method(self, arg):
        f = super
        f().method(arg)





[1] Which is not necessarily a bad thing!

-- 
Steven

[toc] | [prev] | [next] | [standalone]


#56634

FromIan Kelly <ian.g.kelly@gmail.com>
Date2013-10-10 20:33 -0600
Message-ID<mailman.977.1381458865.18130.python-list@python.org>
In reply to#56632
On Thu, Oct 10, 2013 at 8:11 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> One of the side-effects of this being a hack is that this doesn't work:
>
> class X(Y):
>     def method(self, arg):
>         f = super
>         f().method(arg)

Actually, that works just fine.  The compiler sees that super is
accessed within the method and creates the closure necessary to make
it work.  This does fail, however:

f = super
class X(Y):
    def method(self, arg):
        f().method(arg)

[toc] | [prev] | [next] | [standalone]


#56638

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-10-11 03:00 +0000
Message-ID<525769b2$0$29984$c3e8da3$5496439d@news.astraweb.com>
In reply to#56634
On Thu, 10 Oct 2013 20:33:37 -0600, Ian Kelly wrote:

> On Thu, Oct 10, 2013 at 8:11 PM, Steven D'Aprano
> <steve+comp.lang.python@pearwood.info> wrote:
>> One of the side-effects of this being a hack is that this doesn't work:
>>
>> class X(Y):
>>     def method(self, arg):
>>         f = super
>>         f().method(arg)
> 
> Actually, that works just fine.  The compiler sees that super is
> accessed within the method and creates the closure necessary to make it
> work.  This does fail, however:
> 
> f = super
> class X(Y):
>     def method(self, arg):
>         f().method(arg)



Ah, that's the one! Thanks for the correction.

I'll now go and write "I will always test my code snippets before 
posting" on the blackboard one hundred times.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#56648

FromChris Angelico <rosuav@gmail.com>
Date2013-10-11 17:08 +1100
Message-ID<mailman.985.1381471733.18130.python-list@python.org>
In reply to#56638
On Fri, Oct 11, 2013 at 2:00 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> I'll now go and write "I will always test my code snippets before
> posting" on the blackboard one hundred times.

print("I will always test my code snippets before posting\n"*100)

ChrisA

PS. Irony would be having a bug in that because I didn't test it. I
almost didn't, but remembered just before hitting Send.

[toc] | [prev] | [next] | [standalone]


#56651

FromMarco Buttu <marco.buttu@gmail.com>
Date2013-10-11 08:17 +0200
Message-ID<52579809.1040904@gmail.com>
In reply to#56634
On 10/11/2013 04:33 AM, Ian Kelly wrote:

> On Thu, Oct 10, 2013 at 8:11 PM, Steven D'Aprano

>> >One of the side-effects of this being a hack is that this doesn't work:
>> >
>> >class X(Y):
>> >     def method(self, arg):
>> >         f = super
>> >         f().method(arg)

> Actually, that works just fine.  The compiler sees that super is
> accessed within the method and creates the closure necessary to make
> it work.  This does fail, however:
>
> f = super
> class X(Y):
>      def method(self, arg):
>          f().method(arg)

Very interesting! Thanks :)
-- 
Marco Buttu

[toc] | [prev] | [next] | [standalone]


#56650

FromMarco Buttu <marco.buttu@gmail.com>
Date2013-10-11 08:15 +0200
Message-ID<l3851l$tbo$1@speranza.aioe.org>
In reply to#56632
On 10/11/2013 04:11 AM, Steven D'Aprano wrote:

> super() with no arguments is*completely*  a hack[1], and one where GvR
> has said "Never again!" if I remember correctly. I don't think he regrets
> allowing the super compile-time magic, just that it really is magic and
> he doesn't want to make a habit of it.
>
...
> [1] Which is not necessarily a bad thing!

Thanks a lot for this anecdote :)

-- 
Marco Buttu

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web