> 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

Reply via email to