> On 4 Mar 2020, at 17:12, Adam Preble <adam.pre...@gmail.com> wrote:
>
> Months ago, I asked a bunch of stuff about super() and managed to fake it
> well enough to move on to other things for awhile. The day of reckoning came
> this week and I was forced to implement it better for my personal Python
> project. I have a hack in place that makes it work well-enough but I found
> myself frustrated with how shift the super type is. It's both the self and
> the parent class, but not.
>
> If you don't know, you can trap what super() returns some time and poke it
> with a stick. If you print it you'll be able to tell it's definitely unique:
> <super: <class 'Child'>, <Child object>>
>
> If you try to invoke methods on it, it'll invoke the superclass' methods.
> That's what is supposed to happen and basically what already happens when you
> do super().invoke_this_thing() anyways.
>
> Okay, so how is it doing the lookup for that? The child instance and the
> super types' __dict__ are the same. The contents pass an equality comparison
> and are the same if you print them.
Do you know about the Method Resolution Order (MRO) that is in
__class__.__mro__)?
I was very confused by super() until I found out about the MRO. When you call
super() it finds
where the code is in the MRO and then starts looking for a method in classes
before the calling
class.
The following code shows this:
class A:
def __init__(self):
super().__init__()
def fn(self):
return 'A.fn'
class B(A):
def __init__(self):
super().__init__()
class C(B):
def __init__(self):
super().__init__()
def fn(self):
return 'C.fn and super().fn is %r with value %r' % (super().fn,
super().fn())
class D(C):
def __init__(self):
super().__init__()
print(D.__mro__)
obj = D()
print( obj.fn() )
When it is run it prints:
(<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class
'__main__.A'>, <class 'object'>)
C.fn and super().fn is <bound method A.fn of <__main__.D object at
0x10e1728d0>> with value 'A.fn'
When fn() is called on obj the version of fn() in class C is called.
That fn() calls the super().fn and the second print shows that its the class A
fn that is found called.
super starts with the next class after the one it is called in. It is in C so
find C in the MRO and starts with
B. B does not have an fn(). Then it looks in A and finds fn().
Is this what you are looking for?
Barry
>
> They have the same __getattribute__ method wrapper. However, if you dir()
> them you definitely get different stuff. For one, the super type has its
> special variables __self__, __self_class__, and __thisclass__. It's missing
> __dict__ from the dir output. But wait, I just looked at that!
>
> So I'm thinking that __getattr__ is involved, but it's not listed in
> anything. If I use getattr on the super, I'll get the parent methods. If I
> use __getattribute__, I get the child's methods. I get errors every way I've
> conceived of trying to pull out a __getattr__ dunder. No love.
>
> I guess the fundamental question is: what different stuff happens when
> LOAD_ATTR is performed on a super object versus a regular object?
>
> If you are curious about what I'm doing right now, I overrode
> __getattribute__ since that's primarily what I use for attribute lookups
> right now. It defer to the superclass' __getattribute__. If a method pops
> out, it replaces the self with the super's __self__ before kicking it out. I
> feel kind of dirty doing it:
>
> https://github.com/rockobonaparte/cloaca/blob/312758b2abb80320fb3bf344ba540a034875bc4b/LanguageImplementation/DataTypes/PySuperType.cs#L36
>
> If you want to see how I was experimenting with super, here's the code and
> output:
>
> class Parent:
> def __init__(self):
> self.a = 1
>
> def stuff(self):
> print("Parent stuff!")
>
>
> class Child(Parent):
> def __init__(self):
> super().__init__()
> self.b = 2
> self.super_instance = super()
>
> def stuff(self):
> print("Child stuff!")
>
> def only_in_child(self):
> print("Only in child!")
>
>
> c = Child()
> c.super_instance.__init__()
> c.stuff()
> c.super_instance.stuff()
> print(c)
> print(c.super_instance)
> print(c.__init__)
> print(c.super_instance.__init__)
> print(c.stuff)
> print(c.super_instance.stuff)
> print(c.__getattribute__)
> print(c.super_instance.__getattribute__)
> print(dir(c))
> print(dir(c.super_instance))
> print(c.__dict__ == c.super_instance.__dict__)
> print(getattr(c, "__init__"))
> print(getattr(c.super_instance, "__init__"))
> print(c.__getattribute__("__init__"))
> print(c.super_instance.__getattribute__("__init__"))
>
>
>
> Child stuff!
> Parent stuff!
> <__main__.Child object at 0x0000026854D99828>
> <super: <class 'Child'>, <Child object>>
> <bound method Child.__init__ of <__main__.Child object at 0x0000026854D99828>>
> <bound method Parent.__init__ of <__main__.Child object at
> 0x0000026854D99828>>
> <bound method Child.stuff of <__main__.Child object at 0x0000026854D99828>>
> <bound method Parent.stuff of <__main__.Child object at 0x0000026854D99828>>
> <method-wrapper '__getattribute__' of Child object at 0x0000026854D99828>
> <method-wrapper '__getattribute__' of Child object at 0x0000026854D99828>
> ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
> '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
> '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
> '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
> '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'only_in_child',
> 'stuff', 'super_instance']
> ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
> '__ge__', '__get__', '__getattribute__', '__gt__', '__hash__', '__init__',
> '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
> '__reduce_ex__', '__repr__', '__self__', '__self_class__', '__setattr__',
> '__sizeof__', '__str__', '__subclasshook__', '__thisclass__', 'a', 'b',
> 'super_instance']
> True
> <bound method Child.__init__ of <__main__.Child object at 0x0000026854D99828>>
> <bound method Parent.__init__ of <__main__.Child object at
> 0x0000026854D99828>>
> <bound method Child.__init__ of <__main__.Child object at 0x0000026854D99828>>
> <bound method Child.__init__ of <__main__.Child object at 0x0000026854D99828>>
> --
> https://mail.python.org/mailman/listinfo/python-list
>
--
https://mail.python.org/mailman/listinfo/python-list