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-l...@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


--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to