最近、派生クラスメソッドを呼び出すメタクラスで問題が発生しました。たとえばtestA
、クラスメソッドを持つ単純な baseclass を取得しますdo1(a)
class testA(object):
@classmethod
def do1(cls, a):
print "in testA:",cls, a
次に、cls を出力するだけのメタクラスを作成します。
class testMetaA(type):
def __init__(cls,cname,bases,cdict):
print "in testMetaA: %s"%cls
次に、メタクラスを使用してtestB
、期待どおりに動作するサブクラスを構築できます。
class testB(testA):
@classmethod
def do1(cls, a):
print "in testB: %s"%cls
super(testB, cls).do1(a)
__metaclass__=testMetaA
次のように出力されますin testMetaA: <class '__main__.testB'>
。そしてtestB.do1(a)
期待どおりに動作します:
>>> testB.do1('hello')
in testB: <class '__main__.testB'>
in testA: <class '__main__.testB'> hello
super
ただし、次のように" " を含むメタクラス内で classmethod を呼び出そうとするとtestMetaB
、エラーが発生します: NameError: global name 'testC' is not defined
.
class testMetaB(type):
def __init__(cls,cname,bases,cdict):
print "in testMetaB: %s"%cls
cls.do1("hello")
class testC(testA):
@classmethod
def do1(cls, a):
print "in testC: %s"%cls
super(testC, cls).do1(a)
__metaclass__=testMetaB
super(cls, cls)
私は最終的に代わりに使用してそれを解決する方法を見つけましたsuper(testC, cls)
:
class testD(testA):
@classmethod
def do1(cls, a):
print "in testD: %s"%cls
super(cls, cls).do1(a)
__metaclass__=testMetaB
次のように印刷されます。
in testMetaB: <class '__main__.testD'>
in testD: <class '__main__.testD'>
in testA: <class '__main__.testD'> hello
testD.do1(a)
も期待どおりに機能します。
>>> testD.do1('Well done')
in testD: <class '__main__.testD'>
in testA: <class '__main__.testD'> Well done
クラスメソッドでスーパーを使用する最も正しい方法はどれですか? super(cls,cls)
現在のクラス名を明示的に記述する代わりに、常に使用する必要がありますか?
ありがとう!
@jsbueno
コードの一部が派生クラスを動的に作成するなどのトリックに頼っている場合、それは重要です。その名前がクラス自体ではなく別のオブジェクトに割り当てられている場合、クラス名を Super の最初のパラメーターとして使用しないでください。代わりに、クラス メソッドの cls、または
self.__class__
インスタンス メソッドを Super に渡すことができます。
これは、一般的にスーパーにクラス名を使用するのは悪い考えであることを意味しますか?
私自身、通常super(type(self),self)
の代わりにsuper(type(self.__class__),self)
通常の方法で使用しています。を使用する大きな利点があるかどうかはわかりませんself.__class__
。@jsbueno の例をこのように繰り返します。ここでは C を使用しますsuper(type(self),self)
。そのD2()
ため、クラスC
が変更されても動作は変更されません。
>>> class A(object):
def do(self):
print "in class A"
>>> class B(A):
def do(self):
super(B, self).do()
>>> class C(A):
def do(self):
super(type(self),self).do()
>>> D1=B
>>> D2=C
>>> D1().do()
in class A
>>> D2().do()
in class A
>>> class B(A):
def do(self):
print "in new class B"
>>> D1().do()
Traceback (most recent call last):
File "<pyshell#52>", line 1, in <module>
D1().do()
File "<pyshell#37>", line 3, in do
super(B, self).do()
TypeError: super(type, obj): obj must be an instance or subtype of type
>>> class C(A):
def do(self):
print "in new class C"
>>> D2().do()
in class A
@Don Question の提案によると、ここに Python のバージョンを入れます: sys.version= 2.7.2+ (default, Oct 4 2011, 20:06:09) [GCC 4.6.1]