super() in injected methods

Andras Tantos python-list at andras.tantosonline.com
Thu Feb 11 21:40:10 EST 2021


Chris,

Thanks for the reply!

On 2/11/21 11:08 AM, Chris Angelico wrote:
> On Fri, Feb 12, 2021 at 5:54 AM Andras Tantos
> <python-list at andras.tantosonline.com> wrote:
>> Esteemed Python Gurus,
>>
>> I think, I actually know the answer to this question, but - maybe beyond
>> reason - I'm hoping there to be some magic. Consider the following code:
>>
>> from types import MethodType
>>
>> class A(object):
>> pass
>> def m(self, x):
>> print(f"A.m({x})")
>> class B(A):
>> def m(self, x):
>> print(f"B.m({x})")
>> ss = super()
>> ss.m(x)
>>
>> def method(self, s):
>> print(f"method({s})")
>> try:
>> ss = super() # <-- Complains about __class__ cell not being
>> found
>> except:
>> print("I shouldn't need to do this!")
>> ss = super(type(self), self) # <-- Works just fine
>> ss.m(s)
>>
>> a = B()
>> a.m(41)
>> a.m = MethodType(method, a)
>> a.m(42)
>>
>>
>> In the function 'method', I try to access the super() class. Now, of
>> course that makes no sense as a stand-alone function, but it does, once
>> it gets injected as a method into 'a' below.
>>
>> The two-parameter version of the call of course works without a hitch.
> Be careful: the first parameter is supposed to be the class that
> you're currently implementing, which may well NOT be type(self). Given
> that you're attaching to an instance, though, it's probably okay to
> assume you are looking at the leaf class.
Good point, thanks for raising it. That is the of course the reason it's 
not implemented that way by the interpreter. In this particular instance 
that happens to be the correct answer, but generally no, it's not the same.
>
>> I think I actually understand why this is happening (some interpreter
>> magic around super() forcing the insertion of __class__, which that
>> doesn't happen when parsing a stand-alone function). I think I even
>> understand the rationale for it, which is that super() needs to be
>> statically evaluated.
> What happens in the normal case is that __class__ is accessed via
> closure cell from the class block itself. The compiler translates
> super() into super(__class__, self) where 'self' is actually 'whatever
> the first parameter is'.
>
>> Now to the question though: In theory this information (static type of
>> 'self' at the point of method binding to class) is available at the
>> point of method injection, in this example, the next-to-last line of the
>> code. So, is there a way to somehow
>> inject/override/magically-make-it-appear the __class__ cell in 'method'
>> such that super() starts working as expected again?
>>
> Hmm. I don't think it'd work for technical reasons, but in theory, the
> MethodType constructor would be the place to do this. But injecting
> methods into instances (as opposed to classes) is a sufficiently
> unusual thing that it's probably safest to just use the two-arg super
> and have done with it.
>
Yes, MethodType could be a place to deal with this, but - since it 
doesn't - I'm looking for any way to do it outside of it. The question 
of packaging it up into a neat API can wait for another day.

Andras




More information about the Python-list mailing list