当调用super()
以解析到父类方法、实例方法或静态方法的版本时,我们希望将我们所在范围的当前类作为第一个参数传递,以指示我们尝试解析到哪个父类的范围,并作为第二个参数是感兴趣的对象,以指示我们试图将该范围应用于哪个对象。
考虑一个类层次结构A
, B
, 并且C
每个类都是其后一个类的父级, 和a
,b
以及每个类的c
相应实例。
super(B, b)
# resolves to the scope of B's parent i.e. A
# and applies that scope to b, as if b was an instance of A
super(C, c)
# resolves to the scope of C's parent i.e. B
# and applies that scope to c
super(B, c)
# resolves to the scope of B's parent i.e. A
# and applies that scope to c
使用super
静态方法
例如super()
在__new__()
方法中使用
class A(object):
def __new__(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
return super(A, cls).__new__(cls, *a, **kw)
解释:
1- 尽管通常__new__()
将调用类的引用作为其第一个参数,但它在 Python 中不是作为类方法实现的,而是作为静态方法实现的。也就是说,对类的引用必须在__new__()
直接调用时作为第一个参数显式传递:
# if you defined this
class A(object):
def __new__(cls):
pass
# calling this would raise a TypeError due to the missing argument
A.__new__()
# whereas this would be fine
A.__new__(A)
2-当调用super()
到父类时,我们将子类A
作为其第一个参数传递,然后我们传递对感兴趣对象的引用,在这种情况下,它A.__new__(cls)
是调用时传递的类引用。在大多数情况下,它也恰好是对子类的引用。在某些情况下,它可能不是,例如在多代继承的情况下。
super(A, cls)
3-因为作为一般规则__new__()
是一个静态方法,super(A, cls).__new__
也将返回一个静态方法,并且需要显式地提供所有参数,包括对感兴趣对象的引用,在这种情况下cls
。
super(A, cls).__new__(cls, *a, **kw)
4-做同样的事情没有super
class A(object):
def __new__(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
return object.__new__(cls, *a, **kw)
super
与实例方法一起使用
例如super()
从内部使用__init__()
class A(object):
def __init__(self, *a, **kw):
# ...
# you make some changes here
# ...
super(A, self).__init__(*a, **kw)
解释:
1-__init__
是一个实例方法,这意味着它的第一个参数是对实例的引用。当直接从实例调用时,引用是隐式传递的,也就是说你不需要指定它:
# you try calling `__init__()` from the class without specifying an instance
# and a TypeError is raised due to the expected but missing reference
A.__init__() # TypeError ...
# you create an instance
a = A()
# you call `__init__()` from that instance and it works
a.__init__()
# you can also call `__init__()` with the class and explicitly pass the instance
A.__init__(a)
2-当super()
在内部调用时,__init__()
我们将子类作为第一个参数传递,将感兴趣的对象作为第二个参数传递,这通常是对子类实例的引用。
super(A, self)
3- 调用super(A, self)
返回一个代理,该代理将解析范围并将其应用于就self
好像它现在是父类的实例一样。我们称之为代理s
。由于__init__()
是实例方法,因此调用s.__init__(...)
将隐式地将 的引用self
作为第一个参数传递给父级的__init__()
.
4-做同样的事情,super
我们不需要将实例的引用显式传递给父版本的__init__()
.
class A(object):
def __init__(self, *a, **kw):
# ...
# you make some changes here
# ...
object.__init__(self, *a, **kw)
super
与类方法一起使用
class A(object):
@classmethod
def alternate_constructor(cls, *a, **kw):
print "A.alternate_constructor called"
return cls(*a, **kw)
class B(A):
@classmethod
def alternate_constructor(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
print "B.alternate_constructor called"
return super(B, cls).alternate_constructor(*a, **kw)
解释:
1- 可以直接从类中调用类方法,并将对类的引用作为其第一个参数。
# calling directly from the class is fine,
# a reference to the class is passed implicitly
a = A.alternate_constructor()
b = B.alternate_constructor()
2-当在类方法中调用super()
以解析其父版本时,我们希望将当前子类作为第一个参数传递以指示我们尝试解析到哪个父类的范围,并将感兴趣的对象作为第二个参数指示我们想要将该范围应用于哪个对象,通常是对子类本身或其子类之一的引用。
super(B, cls_or_subcls)
3- 调用super(B, cls)
解析为 的范围A
并将其应用于cls
. 由于alternate_constructor()
是一个类方法,调用super(B, cls).alternate_constructor(...)
将隐式传递一个引用cls
作为第一个参数到A
的版本alternate_constructor()
super(B, cls).alternate_constructor()
4-在不使用的情况下做同样的事情,super()
您需要获取对未绑定版本A.alternate_constructor()
(即函数的显式版本)的引用。简单地这样做是行不通的:
class B(A):
@classmethod
def alternate_constructor(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
print "B.alternate_constructor called"
return A.alternate_constructor(cls, *a, **kw)
上述方法不起作用,因为该A.alternate_constructor()
方法将隐式引用A
作为其第一个参数。这里cls
传递的将是它的第二个参数。
class B(A):
@classmethod
def alternate_constructor(cls, *a, **kw):
# ...
# whatever you want to specialize or override here
# ...
print "B.alternate_constructor called"
# first we get a reference to the unbound
# `A.alternate_constructor` function
unbound_func = A.alternate_constructor.im_func
# now we call it and pass our own `cls` as its first argument
return unbound_func(cls, *a, **kw)