什么时候应该使用@classmethod?什么时候应该使用def method(self)?


88

在集成我以前从未使用过的Django应用程序时,我发现了用于定义类中函数的两种不同方式。作者似乎非常有意地使用了它们。第一个是我自己经常使用的:

class Dummy(object):

    def some_function(self,*args,**kwargs):
        do something here
        self is the class instance

另一个是我不使用的,主要是因为我不知道何时使用它,以及什么用途:

class Dummy(object):

    @classmethod
    def some_function(cls,*args,**kwargs):
        do something here
        cls refers to what?

在Python文档中,classmethod装饰器的解释如下:

类方法将类作为隐式第一个参数接收,就像实例方法接收实例一样。

所以我想cls指的是Dummy自己(而class不是实例)。我不完全理解为什么会这样,因为我总是可以这样做:

type(self).do_something_with_the_class

这仅仅是为了清楚起见,还是我错过了最重要的部分:没有它就无法完成的怪异而令人着迷的事情?

Answers:


70

你的猜测是正确的-你明白如何 classmethod的工作。

为什么可以在实例或类上调用这些方法(在两种情况下,类对象都将作为第一个参数传递):

class Dummy(object):

    @classmethod
    def some_function(cls,*args,**kwargs):
        print cls

#both of these will have exactly the same effect
Dummy.some_function()
Dummy().some_function()

关于在实例上使用这些方法:在实例上调用类方法至少有两个主要用途:

  1. self.some_function()some_function根据的实际类型调用的版本self,而不是该调用恰巧出现的类(如果重命名该类,则无需注意);和
  2. 如果some_function需要实现某些协议,但仅调用类对象很有用。

与的区别staticmethod:还有另一种定义不访问实例数据的方法的方法,称为staticmethod。这样就创建了一个根本不接收隐式第一个参数的方法。因此,将不会传递有关调用它的实例或类的任何信息。

In [6]: class Foo(object): some_static = staticmethod(lambda x: x+1)

In [7]: Foo.some_static(1)
Out[7]: 2

In [8]: Foo().some_static(1)
Out[8]: 2

In [9]: class Bar(Foo): some_static = staticmethod(lambda x: x*2)

In [10]: Bar.some_static(1)
Out[10]: 2

In [11]: Bar().some_static(1)
Out[11]: 2

我发现它的主要用途是将现有函数(不会收到self)改编为类(或对象)上的方法。


2
不错的一个:我喜欢将答案分为方式-为什么。据我所知,@classmethod允许访问该函数而无需实例。这正是我在寻找的东西,谢谢。
2012年

1
@marcin真正的鸭子打字确实赋予了它其他维度。更多的是关于不写什么self.foo()时候应该写的东西Bar.foo()
Voo 2012年

5
@Voo实际上self.foo()是可取的,因为它self可能是实现自己的的子类的实例foo
Marcin 2012年

1
@Marcin我认为这取决于您想要实现的目标。但我明白你的意思。
2012年

1
您应该为Baras使用不同的lambda 1+1 == 2 == 1*2,因此无法从显示的结果中分辨出Bar().static_method实际调用的结果。
乔治五世·赖利

0

基本上,当您意识到方法的定义不会被更改或覆盖时,应该使用@classmethod。

另外,从理论上讲,类方法比对象方法要快,因为不需要实例化并且需要较少的内存。


-3

如果添加装饰器@classmethod,则意味着您将使该方法成为Java或C ++的静态方法。(我猜static方法是一个通用术语;))Python也有@staticmethod。classmethod和staticmethod之间的区别在于您是否可以使用参数或classname本身访问class或static变量。

class TestMethod(object):
    cls_var = 1
    @classmethod
    def class_method(cls):
        cls.cls_var += 1
        print cls.cls_var

    @staticmethod
    def static_method():
        TestMethod.cls_var += 1
        print TestMethod.cls_var
#call each method from class itself.
TestMethod.class_method()
TestMethod.static_method()

#construct instances
testMethodInst1 = TestMethod()    
testMethodInst2 = TestMethod()   

#call each method from instances
testMethodInst1.class_method()
testMethodInst2.static_method()

所有这些类都将cls.cls_var增加1并打印出来。

每个在相同作用域上使用相同名称的类或使用这些类构造的实例都将共享这些方法。只有一个TestMethod.cls_var,也只有一个TestMethod.class_method(),TestMethod.static_method()

和重要的问题。为什么需要这些方法。

当您将该类设置为工厂或只需要初始化一次类时,classmethod或staticmethod很有用。就像一次打开文件一样,并使用feed方法逐行读取文件。


2
(a)静态方法是另一回事;(b)并非每个班级都共享班级方法。
Marcin

@Marcin感谢您让我知道我不清楚的定义以及所有其他内容。
瑞安·金
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.