クラスメソッド、インスタンスメソッド、または静的メソッドの親のバージョンに解決するために呼び出す場合super()
、最初の引数として現在のスコープを持つ現在のクラスを渡し、解決しようとしている親のスコープを示します。 2 番目の引数は、対象のオブジェクトで、そのスコープを適用しようとしているオブジェクトを示します。
クラス階層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
staticmethod での使用
たとえば、メソッド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)
説明:
__new__()
1-呼び出し元クラスへの参照を最初のパラメータとして使用するのが通常ですが、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__()
staticmethod であるためsuper(A, cls).__new__
、 staticmethod も返すため、関心のあるオブジェクトへの参照を含むすべての引数を明示的に指定する必要があります。この場合は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)
super()
2-内部で呼び出す場合__init__()
、子クラスを最初の引数として渡し、対象のオブジェクトを 2 番目の引数として渡します。これは通常、子クラスのインスタンスへの参照です。
super(A, self)
3-呼び出しは、スコープを解決し、それを親クラスのインスタンスであるかのようにsuper(A, self)
適用するプロキシを返します。self
その proxy を呼び出しましょう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()
親のバージョンに解決するためにクラスメソッド内で呼び出す場合、現在の子クラスを最初の引数として渡し、解決しようとしている親のスコープを示し、対象のオブジェクトを 2 番目の引数として渡します。そのスコープをどのオブジェクトに適用するかを示します。これは通常、子クラス自体またはそのサブクラスの 1 つへの参照です。
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
で渡されるのは、その 2 番目の引数になります。
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)