Python中的@staticmethod和@classmethod有什么区别?
用@staticmethod装饰的函数和用@classmethod装饰的函数有什么区别?
解决方案
静态方法是一种对所调用的类或者实例一无所知的方法。它只是获取传递的参数,没有隐式的第一个参数。在Python中,它基本上是没有用的-我们可以仅使用模块函数代替静态方法。
另一方面,类方法是一种方法,它会将调用它的类或者调用它的实例的类作为第一个参数传递给它。当我们希望该方法成为类的工厂时,这很有用:由于它获得了作为第一个参数调用的实际类,因此即使在涉及子类的情况下,也始终可以实例化正确的类。例如,观察当调用子类时,类方法dict.fromkeys()如何返回子类的实例:
>>> class DictSubclass(dict): ... def __repr__(self): ... return "DictSubclass" ... >>> dict.fromkeys("abc") {'a': None, 'c': None, 'b': None} >>> DictSubclass.fromkeys("abc") DictSubclass >>>
基本上,@classmethod是一种方法,其第一个参数是从其调用的类(而不是类实例),而@staticmethod没有任何隐式参数。
@staticmethod只是禁用默认函数作为方法描述符。 classmethod将函数包装在一个可调用的容器中,该容器将对拥有类的引用作为第一个参数传递:
>>> class C(object): ... pass ... >>> def f(): ... pass ... >>> staticmethod(f).__get__(None, C) <function f at 0x5c1cf0> >>> classmethod(f).__get__(None, C) <bound method type.f of <class '__main__.C'>>
实际上,classmethod
具有运行时开销,但可以访问拥有的类。另外,我建议使用元类并将类方法放在该元类上:
>>> class CMeta(type): ... def foo(cls): ... print cls ... >>> class C(object): ... __metaclass__ = CMeta ... >>> C.foo() <class '__main__.C'>
这是关于这个问题的简短文章
@staticmethod function is nothing more than a function defined inside a class. It is callable without instantiating the class first. It’s definition is immutable via inheritance. @classmethod function also callable without instantiating the class, but its definition follows Sub class, not Parent class, via inheritance. That’s because the first argument for @classmethod function must always be cls (class).
也许有一些示例代码会有所帮助:请注意foo
,class_foo
和static_foo
的调用签名的区别:
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 a=A()
以下是对象实例调用方法的常用方法。对象实例" a"作为第一个参数隐式传递。
a.foo(1) # executing foo(<__main__.A object at 0xb7dbef0c>,1)
使用classmethods时,对象实例的类作为第一个参数而不是self
隐式传递。
a.class_foo(1) # executing class_foo(<class '__main__.A'>,1)
我们也可以使用该类调用class_foo
。实际上,如果我们将某项定义为
一个类方法,可能是因为我们打算从类而不是从类实例中调用它。 A.foo(1)会引发TypeError,但是A.class_foo(1)可以正常工作:
A.class_foo(1) # executing class_foo(<class '__main__.A'>,1)
人们发现类方法的一种用途是创建可继承的替代构造函数。
使用静态方法时," self"(对象实例)和" cls"(类)都不会隐式传递为第一个参数。它们的行为类似于普通函数,只是我们可以从实例或者类中调用它们:
a.static_foo(1) # executing static_foo(1) A.static_foo('hi') # executing static_foo(hi)
静态方法用于对与类之间具有某种逻辑联系的函数进行分组。
foo只是一个函数,但是当我们调用a.foo时,我们不仅会获得该函数,
我们将获得该函数的"部分应用"版本,并将对象实例" a"绑定为该函数的第一个参数。 foo需要2个参数,而a.foo仅需要1个参数。
" a"绑定到" foo"。这就是下面的术语"绑定"的含义:
print(a.foo) # <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
使用a.class_foo
时,a'不会绑定到
class_foo,而是将类
A绑定到
class_foo`。
print(a.class_foo) # <bound method type.class_foo of <class '__main__.A'>>
在这里,使用静态方法,即使它是一种方法,a.static_foo
也会返回
一个很好的'ole函数,没有参数绑定。 static_foo
需要1个参数,并且a.static_foo
也需要1个参数。
print(a.static_foo) # <function static_foo at 0xb7d479cc>
当然,当我们改为使用类A调用static_foo时,也会发生同样的事情。
print(A.static_foo) # <function static_foo at 0xb7d479cc>
官方python文档:
@classmethod
A class method receives the class as implicit first argument, just like an instance method receives the instance. To declare a class method, use this idiom: class C: @classmethod def f(cls, arg1, arg2, ...): ... The @classmethod form is a function decorator – see the description of function definitions in Function definitions for details. It can be called either on the class (such as C.f()) or on an instance (such as C().f()). The instance is ignored except for its class. If a class method is called for a derived class, the derived class object is passed as the implied first argument. Class methods are different than C++ or Java static methods. If you want those, see staticmethod() in this section.
@staticmethod
A static method does not receive an implicit first argument. To declare a static method, use this idiom: class C: @staticmethod def f(arg1, arg2, ...): ... The @staticmethod form is a function decorator – see the description of function definitions in Function definitions for details. It can be called either on the class (such as C.f()) or on an instance (such as C().f()). The instance is ignored except for its class. Static methods in Python are similar to those found in Java or C++. For a more advanced concept, see classmethod() in this section.