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

From here :

super( [ type [ , object-or-type ]] ) 

Returns a proxy object that delegates method calls to the parent or sibling type class. This is useful for accessing inherited methods that have been overridden in a class. The search order is the same as for getattr() , except that type itself is skipped.

If the second argument is omitted, a super unbound object is returned.

If the second argument is an object, isinstance(obj, type) should be true.

If the second argument is type , issubclass(type2, type) should be true (this is useful for classmethods).

  • If I'm right, type is a class and class is a type. The class is an object, so the type is also an object. Why does the quote distinguish two cases when the second argument is an object when it is a type?

  • When the second argument is a type, why should issubclass(type2, type) be true?

  • What is the type of super object returned by super in each of the three cases, respectively? Or how do you determine the type of super object returned by super ?

    When the second argument is an object because "The search order is the same as that of getattr() , except that type itself is skipped", I guessed that the type of the superobject returned by the super function must be a subclass of any ancestor class of the first type argument but I found that this is not really testing with issubclass . So I didn’t understand something?

+5
source share
2 answers

You seem to be confusing the word type with type() . Here they simply refer to the first argument passed to super() .

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

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

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

What actually happens is that super().__getattribute__ accepts the MRO of the second argument (either type(instance).__mro__ , or cls.__mro__ , depending on how isinstance() or issubclass() was true) , find the first argument in this sequence, and then start testing the attributes. Since the MRO is scanned first (type) of the second argument, it needs to be found, so the constraints are what they are.

In Pure Python, this is what super() does (simplified to focus on only two argument behaviors):

 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) 
+4
source

only for point 3 about type super in 3 cases (2 are similar at first):

 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 type print(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 type print(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 object super(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__) #None print(b_sup.__self_class__) #None print(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 type print(c_sup.__self__) #<class '__main__.C'> print(c_sup.__self_class__) #<class '__main__.C'> print(c_sup.__thisclass__) #<class '__main__.A'> 
+2
source

Source: https://habr.com/ru/post/1269644/


All Articles