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.

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

Reply via email to