From here:
super( [ type [ , object-or-type ]] )
Return a proxy object that delegates method calls to a parent or sibling class of
type
. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used bygetattr()
except that thetype
itself is skipped.If the second argument is omitted, the super object returned is unbound.
If the second argument is an object,
isinstance(obj, type)
must be true.If the second argument is a type,
issubclass(type2, type)
must be true (this is useful for classmethods).
If I am correct, a type is a class, and a class is a type. A class is an object, so a type is also an object. Why does the quote distinguish the two cases when the second argument being an object when it is a type?
When the second argument is a type, why is issubclass(type2, type)
required to be true?
What is the type of the super object returned by super
in each of the three cases respectively? Or how do you determine the type of the super object returned by super
?
When the second argument is an object, because "The search order is same as that used by getattr()
except that the type
itself is skipped", I guessed that the type of the superobject returned by super
function should be a subclass of any ancestry class of the first argument type
, but I found that it is actually not by testing with issubclass
. So did I misunderstand something?
The super() function is used to give access to methods and properties of a parent or sibling class. The super() function returns an object that represents the parent class.
Understanding Python super() with __init__() methodsThe super function returns a temporary object of the superclass that allows access to all of its methods to its child class. Note: For more information, refer to Inheritance in Python.
In general it is necessary. And it's often necessary for it to be the first call in your init. It first calls the init function of the parent class ( dict ).
The class from which a class inherits is called the parent or superclass. A class which inherits from a superclass is called a subclass, also called heir class or child class.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With