python - 在 python 中派生类方法的正确方法是什么?

标签 python superclass metaclass class-method

最近,我遇到了元类调用派生类方法的问题。 例如,我得到一个简单的基类 testA ,它有一个类方法 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”的元类中的类方法,如下所示 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 的最正确方法是什么?是否应该始终使用 super(cls,cls)而不是显式地写一个当前类名?

谢谢!

@jsbueno

If some piece of code resorts to tricks like dynamically creating derived classes, that is important - one should not use the class name as first parametere to Super if that name is assigned to another object than the class itself. Instead, cls for class methods, or self.__class__ for instance methods can be passed to Super.

这是否意味着通常将类名用于 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]

最佳答案

However, if I try to call the classmethod inside the metaclass which contains a "super" as following testMetaB, it will raise an error: NameError: global name 'testC' is not defined.

名字TestC只有在 MetaClass 完成它的工作后才会绑定(bind)到新类 - 那是在从它的 __init__ 返回之后(在 __init__ 之前,即 __new__ )方法。

当我们使用“super”调用将类名作为第一个参数时,类名并没有神奇地出现在那里:它是一个(模块)全局变量,类本身被分配给它 - 在正常情况下。

在这种情况下,尚未分配名称 - 但是,由于它是一个类方法,因此您可以引用 cls 中的类变量 - 这就是它起作用的原因。

如果某些代码采用动态创建派生类等技巧,那很重要 - 如果该名称被分配给另一个对象而不是类本身,则不应将类名用作 Super 的第一个参数。相反,cls对于类方法,或 self.__class__例如方法可以传递给 Super。

这是一个片段,显示了类名的全局名称绑定(bind)是 super 所采用的:

>>> class A(object):
...   def do(self):
...      print "In class A"
... 
>>> class B(A):
...   def do(self):
...     super(B, self).do()
... 
>>> C = B
>>> C().do()
In class A
>>> class B(object):
...   def do(self):
...      print "in new class B"
... 
>>> C().do()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in do
TypeError: super(type, obj): obj must be an instance or subtype of type
>>> 

关于python - 在 python 中派生类方法的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11469292/

相关文章:

python - 元类的继承

python - 使用 pandas 解析文件时 Airflow Worker 不理解文件编码

python - 在 python 中使用 beautifulsoup 有问题

java - 重写父类(super class)非抽象方法。访问父类(super class)中的私有(private)属性(?)

python - 用元类实现单例

python - Python 3 中的 __metaclass__

python - 在新行上打印每个句子

python - 在模型定义中过滤相关模型的问题

java - 从子类返回数据

python - 调用重写的方法,父类(super class)调用重写的方法