Articles
Screencasts
Exercises
Training
Pastebin
Gift
/
Sign Up
Sign In
The built-in super "function" re-implemented in Python... because I can?
Editable Code
"""The built-in super "function" re-implemented in Python... because I can?""" import inspect _SENTINEL = object() # https://trey.io/sentinel class super: """The built-in super "function" re-implemented.""" def __new__(cls, type=_SENTINEL, obj=None): # super() or super(MyClass), but not super(MyClass, my_instance) if type is _SENTINEL or obj is None: frame = inspect.stack()[1].frame # super() with no args checks __class__ slot in outer frame if type is _SENTINEL: type = frame.f_locals["__class__"] # When no "self" specified, get first argument from outer frame if obj is None: first_arg = inspect.getargvalues(frame).args[0] obj = frame.f_locals[first_arg] # The built-in super object exposes these 3 dunder attributes self = object.__new__(cls) self.__thisclass__ = type self.__self__ = obj if isinstance(obj, type): self.__self_class__ = obj.__class__ elif issubclass(obj, type): self.__self_class__ = obj else: raise TypeError( "super(type, obj): obj must be an instance or subtype of type" ) return self def __getattribute__(self, attr): # Use object.__getattribute__ for lookups to avoid infinite recursion this = object.__getattribute__(self, "__thisclass__") self_class = object.__getattribute__(self, "__self_class__") obj = object.__getattribute__(self, "__self__") # Get the method resolution order from __thisclass__ onward this_mro_index = self_class.__mro__.index(this) method_resolution_order = self_class.__mro__[this_mro_index+1:] # Find method/attribute in first class after ours that has a match for cls in method_resolution_order: if attr in cls.__dict__: value = cls.__dict__[attr] # this is how self-binding works (methods are descriptors) if hasattr(value, "__get__"): value = value.__get__(obj) return value # Should raise an attribute error raise object.__getattribute__(self, attr) def __repr__(self): this = object.__getattribute__(self, "__thisclass__") self_class = object.__getattribute__(self, "__self_class__") return f"<super: {this}, <{self_class.__name__} object>>" # Test it out! if __name__ == "__main__": class Parent: def __init__(self): print("Parent.__init__") class Mixin1: def __init__(self): print("Mixin1.__init__") super().__init__() class Mixin2: def __init__(self): print("Mixin2.__init__") super().__init__() class Child(Parent): def __init__(self): print("Child.__init__") super().__init__() class Grandchild(Mixin1, Mixin2, Child): def __init__(self): print("Grandchild.__init__") super().__init__() print("start!") x = Grandchild() print("done!")
1747 views
Copy
Code copied
Run
in Browser
pym.dev/p/2f95p/
URL copied
Need to share some Python code?
New Python snippet