What is the type of the super object returned by super()? What is the type of the super object returned by super()? python-3.x python-3.x

What is the type of the super object returned by super()?


You seem to be confusing the word type with the type() built-in. Here they simply references the first argument passed into super().

What the documentation tells you is that if you pass in two arguments, then the second argument either has to be an instance of the first argument, or it has to be a subclass. In other words, either isinstance(first_argument, second_argument) or issubclass(first_argument, second_argument) must be true. There is no other meaning here.

Just like int() or str() or any of the other built-in types, the type of the object returned by calling super() is that type. There are no separate types returned for different arguments. See the C source code defining the object.

The super() object implements a __getattribute__ hook that implements specific attribute behaviour. The documentation tells you that the rules for attribute lookups are the same as for getattr() (but with the documented MRO skip), but that does not mean that super() returns an ancestor class.

What actually happens is that super().__getattribute__ takes the MRO of the second argument (either type(instance).__mro__ or cls.__mro__, depending on wether isinstance() or issubclass() was true), find the first argument in that sequence and start testing for attributes after that. Because the MRO is scanned for the (type of) the second argument first, it does have to be findable, which is why the constraints are what they are.

In Pure Python, this is what super() does (simplified to focus on just the two argument behaviour):

def _supercheck(type_, obj):    try:        if issubclass(obj, type_):            return obj    except TypeError:        # obj is not a type so issubclass throws a TypeError        pass    if isinstance(obj, type_):        return type(obj)    raise TypeError(        "super(type, obj): obj must be an instance or subtype of type")class super_:    def __init__(self, type_, obj):        # simplified for the two-argument case        self.type_ = type_        self.obj = obj        self.obj_type = _supercheck(type_, obj)    def __getattribute__(self, name):        if name == '__class__':            # __class__ should always come from this object, not            # the represented MRO.            return super().__getattribute__(name)        # avoid infinite recursion issues        sd = super().__getattribute__('__dict__')        starttype = sd['obj_type']        type_ = sd['type_']        obj = sd['obj']        mro = iter(starttype.__mro__)        # skip past the start type in the MRO        for tp in mro:            if tp == type_:                break        # Search for the attribute on the remainder of the MRO        for tp in mro:            attrs = vars(tp)            if name in attrs:                res = attrs[name]                # if it is a descriptor object, bind it                descr = getattr(type(res), '__get__', None)                if descr is not None:                    res = descr(                        res,                        None if obj is starttype else obj,                        starttype)                return res        return super().__getattribute__(name)


just for the point 3 about the type super in the 3 cases (2 first are similar):

class A(object):    def sup(self):        return (super(A, self))class A1(object):    def sup(self):        return (super())class B(object):          def sup(self):        return (super(B))  class C(A):    def sup(self):        return (super(A,C))      a = A()a_sup = a.sup()print(type(a_sup))  #<class 'super'>print(a_sup.__doc__)  #The most base typeprint(a_sup.__self__)  #<__main__.A object at 0x7f9d0d2d8668>print(a_sup.__self_class__) #<class '__main__.A'>print(a_sup.__thisclass__)  #<class '__main__.A'>print()  a1 = A1()a_sup = a1.sup()print(type(a_sup))  #<class 'super'>print(a_sup.__doc__)  #The most base typeprint(a_sup.__self__)  #<__main__.A1 object at 0x7f9d0d2d86d8>print(a_sup.__self_class__) #<class '__main__.A1'>print(a_sup.__thisclass__) #<class '__main__.A1'>print()    b = B()b_sup = b.sup()print(type(b_sup))  #<class 'super'>print(b_sup.__doc__) '''super() -> same as super(__class__, <first argument>)super(type) -> unbound super objectsuper(type, obj) -> bound super object; requires isinstance(obj, type)super(type, type2) -> bound super object; requires issubclass(type2, type)Typical use to call a cooperative superclass method:class C(B):    def meth(self, arg):        super().meth(arg)This works for class methods too:class C(B):    @classmethod    def cmeth(cls, arg):        super().cmeth(arg)'''        print(b_sup.__self__)  #Noneprint(b_sup.__self_class__)  #Noneprint(b_sup.__thisclass__)  #<class '__main__.B'>print()c=C()c_sup = c.sup()print(type(c_sup))  #<class 'super'>print(c_sup.__doc__) #The most base typeprint(c_sup.__self__) #<class '__main__.C'>print(c_sup.__self_class__) #<class '__main__.C'>print(c_sup.__thisclass__) #<class '__main__.A'>