在同一个Python类中调用method、classmethod、staticmethod

Posted

技术标签:

【中文标题】在同一个Python类中调用method、classmethod、staticmethod【英文标题】:Calling method, classmethod, staticmethod in the same Python class 【发布时间】:2018-04-15 18:08:37 【问题描述】:

从一个著名的例子中,我了解到 Python 类中方法、类方法和静态方法的区别。

来源: What is the difference between @staticmethod and @classmethod in Python?

class A(object):
    def foo(self,x):
        print "executing foo(%s,%s)"%(self,x)

    @classmethod
    def class_foo(cls,x):
        print "executing class_foo(%s,%s)"%(cls,x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)"%x   
    # My Guesses
    def My_Question(self,x):
        self.foo(x)
        A.class_foo(x)
        A.static_foo(x)

a=A()

现在我想知道,如何在类中调用方法,@classmethod@staticmethod

我把我的猜测放在上面的My_Question函数中,如果我有任何错误,请纠正我。

【问题讨论】:

你所拥有的是正确的。也可以对所有 3 使用 self 【参考方案1】:

是的,你的猜测会起作用。请注意,在类外部调用 staticmethods 和 classmethods 也是可能的/正常的:

class A():
    ...

A.class_foo()
A.static_foo()

还要注意常规实例方法中,习惯上直接在实例(self)而不是类(A)上调用静态方法和类方法:

class A():
    def instance_method(self):
        self.class_foo()
        self.static_foo()

这允许继承按您的预期工作——如果我从A 创建一个B 子类,如果我调用B.instance_method(),我的class_foo 函数将得到B 而不是A作为 cls 参数 -- 并且可能,如果我在 B 上覆盖 static_foo 以执行与 A.static_foo 略有不同的操作,这也将允许调用覆盖的版本。

一些例子可能会更清楚地说明这一点:

class A(object):
    @staticmethod
    def static():
        print("Static, in A")

    @staticmethod
    def staticoverride():
        print("Static, in A, overrideable")

    @classmethod
    def clsmethod(cls):
        print("class, in A", cls)

    @classmethod
    def clsmethodoverrideable(cls):
        print("class, in A, overridable", cls)

    def instance_method(self):
        self.static()
        self.staticoverride()
        self.clsmethod()
        self.clsmethodoverride()

class B(A):
    @classmethod
    def clsmethodoverrideable(cls):
        print("class, in B, overridable", cls)

    @staticmethod
    def staticoverride():
        print("Static, in B, overrideable")


a = A()
b = B()
a.instance_method()
b.instance_method()

...

运行之后,尝试将instance_method 中的所有self. 更改为A.。重新运行并比较。您会看到所有对B 的引用都已消失(即使您正在调用b.instance_method())。这就是为什么要使用self 而不是类的原因。

【讨论】:

我在引用帖子的最佳答案中看到,@classmethod 绑定到类,并且必须像普通类方法的“self”一样包含一个“cls”。我想知道“cls”和“self”是否有任何实际含义,所以我们必须使用这两个字符串?还有为什么不使用 cls.class_foo(x) 而不是 self.class_foo(x)? 名称selfcls约定。你可以使用任何你想要的名字,但是如果你偏离了正常的约定,任何阅读你的代码的人都可能会非常大声地对你大喊大叫:-)。在classmethod 中,第一个参数是,而在普通方法中,第一个参数是类的实例。这是您的示例代码中Aa 之间的区别。 -- 至于“为什么不使用cls.class_foo(x)” -- 如果你从另一个类方法调用一个类方法,你使用它。在实例方法中,名称 cls 未定义(使用我的示例代码尝试)。【参考方案2】:

正如@wim 所说,您所拥有的是正确的。这是调用My_Question 时的输出。

>>> a.My_Question("My_Answer=D")
executing foo(<__main__.A object at 0x0000015790FF4668>,My_Answer=D)
executing class_foo(<class '__main__.A'>,My_Answer=D)
executing static_foo(My_Answer=D)

【讨论】:

以上是关于在同一个Python类中调用method、classmethod、staticmethod的主要内容,如果未能解决你的问题,请参考以下文章

Python OOP-static method,class method and instance method

java反射中method类中的invoke方法作用

android 回调机制应用场景

通过反射获取及调用方法(Method)

C#将一个类中的数值赋值给另一个类 两个相同类型的类,例如 Class c1; Clas

关于Python的super用法研究