用
也许一些示例代码会有所帮助:注意
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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() |
下面是对象实例调用方法的通常方式。对象实例
1 2 | a.foo(1) # executing foo(<__main__.A object at 0xb7dbef0c>,1) |
使用classmethods,对象实例的类被隐式地传递为第一个参数,而不是
1 2 | a.class_foo(1) # executing class_foo(<class '__main__.A'>,1) |
您还可以使用该类调用
1 2 | A.class_foo(1) # executing class_foo(<class '__main__.A'>,1) |
人们发现类方法的一个用途是创建可继承的替代构造函数。
对于静态方法,既不会隐式地传递
1 2 3 4 5 | a.static_foo(1) # executing static_foo(1) A.static_foo('hi') # executing static_foo(hi) |
静态方法用于将与类具有某种逻辑连接的函数分组到类。
1 2 | print(a.foo) # <bound method A.foo of <__main__.A object at 0xb7d52f0c>> |
对于
1 2 | print(a.class_foo) # <bound method type.class_foo of <class '__main__.A'>> |
在这里,使用staticmethod,即使它是一个方法,
1 2 | print(a.static_foo) # <function static_foo at 0xb7d479cc> |
当然,当您使用类
1 2 | print(A.static_foo) # <function static_foo at 0xb7d479cc> |
staticmethod是一个对调用它的类或实例一无所知的方法。它只获取传递的参数,没有隐式的第一个参数。它在Python中基本上是无用的——您可以只使用模块函数而不是静态方法。
另一方面,classmethod是作为第一个参数传递它所调用的类或它所调用实例的类的方法。当您希望方法是类的工厂时,这是很有用的:因为它获取了作为第一个参数被调用的实际类,所以您总是可以实例化正确的类,即使涉及到子类。例如,观察类方法
1 2 3 4 5 6 7 8 9 | >>> class DictSubclass(dict): ... def __repr__(self): ... return"DictSubclass" ... >>> dict.fromkeys("abc") {'a': None, 'c': None, 'b': None} >>> DictSubclass.fromkeys("abc") DictSubclass >>> |
基本上
官方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:
1
2
3 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 asC.f() ) or on an instance
(such asC().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, seestaticmethod() in this
section.
@staticmethod
A static method does not receive an
implicit first argument. To declare a
static method, use this idiom:
1
2
3 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 asC.f() ) or on an instance
(such asC().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.
这里有一篇关于这个问题的短文
@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).
要决定是使用@staticmethod还是@classmethod,您必须查看方法的内部。如果您的方法访问类中的其他变量/方法,那么使用@classmethod。另一方面,如果您的方法没有触及类的任何其他部分,那么使用@staticmethod。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | class Apple: _counter = 0 @staticmethod def about_apple(): print('Apple is good for you.') # note you can still access other member of the class # but you have to use the class instance # which is not very nice, because you have repeat yourself # # For example: # @staticmethod # print('Number of apples have been juiced: %s' % Apple._counter) # # @classmethod # print('Number of apples have been juiced: %s' % cls._counter) # # @classmethod is especially useful when you move your function to other class, # you don't have to rename the class reference @classmethod def make_apple_juice(cls, number_of_apples): print('Make juice:') for i in range(number_of_apples): cls._juice_this(i) @classmethod def _juice_this(cls, apple): print('Juicing %d...' % apple) cls._counter += 1 |
What is the difference between @staticmethod and @classmethod in Python?
你可能见过这样的Python代码伪代码,它演示了各种方法类型的签名,并提供了一个文档字符串来解释每种方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Foo(object): def a_normal_instance_method(self, arg_1, kwarg_2=None): ''' Return a value that is a function of the instance with its attributes, and other arguments such as arg_1 and kwarg2 ''' @staticmethod def a_static_method(arg_0): ''' Return a value that is a function of arg_0. It does not know the instance or class it is called from. ''' @classmethod def a_class_method(cls, arg1): ''' Return a value that is a function of the class and other arguments. respects subclassing, it is called with the class it is called from. ''' |
常规实例方法
首先,我将解释
例如,这是一个字符串的实例:
1 | ', ' |
如果我们对这个字符串使用实例方法
1 2 | >>> ', '.join(['a', 'b', 'c']) 'a, b, c' |
绑定方法
实例方法可以通过点查找绑定,以供以后使用。
例如,它将
1 | >>> join_with_colons = ':'.join |
之后我们可以用这个函数它已经有第一个参数绑定。这样,它就像一个局部函数作用于实例:
1 2 3 4 | >>> join_with_colons('abcde') 'a:b:c:d:e' >>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF']) 'FF:FF:FF:FF:FF:FF' |
静态方法
静态方法不接受实例作为参数。
它非常类似于模块级函数。
但是,模块级函数必须驻留在模块中,并被特别导入到使用它的其他地方。
但是,如果将它附加到对象上,它也会通过导入和继承方便地跟随对象。
静态方法的一个例子是
1 2 3 4 5 | # demonstrate same function whether called from instance or not: >>> ', '.maketrans('ABC', 'abc') {65: 97, 66: 98, 67: 99} >>> str.maketrans('ABC', 'abc') {65: 97, 66: 98, 67: 99} |
在python2中,你必须从越来越没用的string模块中导入这个函数:
1 2 3 | >>> import string >>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc')) 'abcDEFG' |
类方法
类方法与实例方法类似,它接受隐式的第一个参数,但是它不接受实例,而是接受类。为了更好地使用语义,这些构造函数经常被用作替代构造函数,并且它将支持继承。
内建类方法最典型的例子是
1 2 | >>> dict.fromkeys(['a', 'b', 'c']) {'c': None, 'b': None, 'a': None} |
当我们子类化dict时,我们可以使用相同的构造函数,它创建子类的实例。
1 2 3 4 5 6 | >>> class MyDict(dict): 'A dict subclass, use to demo classmethods' >>> md = MyDict.fromkeys(['a', 'b', 'c']) >>> md {'a': None, 'c': None, 'b': None} >>> type(md) <class '__main__.MyDict'> |
有关其他替代构造函数的类似示例,请参阅panda源代码,并请参阅关于
@decorator是在python 2.4中添加的,如果您使用的是python < 2.4,则可以使用classmethod()和staticmethod()函数。
例如,如果你想创建一个工厂方法(一个函数返回一个类的不同实现的实例,这取决于它得到的参数),你可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class Cluster(object): def _is_cluster_for(cls, name): """ see if this class is the cluster with this name this is a classmethod """ return cls.__name__ == name _is_cluster_for = classmethod(_is_cluster_for) #static method def getCluster(name): """ static factory method, should be in Cluster class returns a cluster object for the given name """ for cls in Cluster.__subclasses__(): if cls._is_cluster_for(name): return cls() getCluster = staticmethod(getCluster) |
还要注意,这是一个使用类方法和静态方法的好例子,静态方法显然属于类,因为它在内部使用类集群。classmethod只需要关于类的信息,而不需要对象的实例。
让
我认为更好的问题是"什么时候使用@classmethod和@staticmethod?"
@classmethod允许您轻松访问与类定义关联的私有成员。这是实现单例或控制已创建对象实例数量的工厂类的好方法。
@staticmethod提供了有限的性能提升,但是我还没有看到在类中有效地使用静态方法,而不能作为类之外的独立函数来实现。
静态方法:
没有自参数的简单函数。处理类属性;而不是实例属性。可以通过类和实例调用。内置函数staticmethod()用于创建它们。静态方法的好处:
它在类范围内本地化函数名它将函数代码移动到更靠近使用它的地方与模块级函数相比,导入函数更方便,因为不必特别导入每个方法
1 2 3 | @staticmethod def some_static_method(*args, **kwds): pass |
类方法:
第一个参数为classname的函数。可以通过类和实例调用。这些是用classmethod内建函数创建的。
1 2 3 | @classmethod def some_class_method(cls, *args, **kwds): pass |
1 2 3 4 5 6 7 8 9 10 | >>> 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'>> |
事实上,
1 2 3 4 5 6 7 8 9 | >>> class CMeta(type): ... def foo(cls): ... print cls ... >>> class C(object): ... __metaclass__ = CMeta ... >>> C.foo() <class '__main__.C'> |
我开始用c++学习编程语言,然后是Java和Python,所以这个问题也困扰着我,直到我理解了它们的简单用法。
类方法:Python不同于Java和c++,它没有构造函数重载。为此,可以使用
假设我们有一个
1 2 3 4 5 | class Person(object): def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name |
现在,如果需要创建一个只使用一个名称的类,仅仅使用一个
当您试图创建一个对象(实例)时,这将给您一个错误。
1 2 3 4 5 6 7 8 | class Person(object): def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name def __init__(self, first_name): self.first_name = first_name |
但是,您可以使用下面提到的
1 2 3 4 5 6 7 8 9 | class Person(object): def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name @classmethod def get_person(cls, first_name): return cls(first_name,"") |
静态方法::这相当简单,它不绑定到实例或类,您可以简单地使用类名调用它。
因此,让我们在上面的例子中说,您需要验证
1 2 3 | @staticmethod def validate_name(name): return len(name) <= 20 |
你可以简单地用类名调用
1 | Person.validate_name("Gaurang Shah") |
关于如何在Python中使用静态、类或抽象方法的权威指南是本主题的一个很好的链接,并将其总结如下。
让我先说明用@classmethod修饰的方法和用@staticmethod修饰的方法之间的相似性。
相似性:它们都可以在类本身上调用,而不仅仅是类的实例。它们都是类的方法。
区别:类方法将接受类本身作为第一个参数,而静态方法不接受。
所以静态方法,在某种意义上,不绑定到类本身,只是挂在那里,因为它可能有相关的功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | >>> class Klaus: @classmethod def classmthd(*args): return args @staticmethod def staticmthd(*args): return args # 1. Call classmethod without any arg >>> Klaus.classmthd() (__main__.Klaus,) # the class gets passed as the first argument # 2. Call classmethod with 1 arg >>> Klaus.classmthd('chumma') (__main__.Klaus, 'chumma') # 3. Call staticmethod without any arg >>> Klaus.staticmthd() () # 4. Call staticmethod with 1 arg >>> Klaus.staticmthd('chumma') ('chumma',) |
关于静态方法vs . classmethod的另一个考虑是继承。假设你有以下课程:
1 2 3 4 | class Foo(object): @staticmethod def bar(): return"In Foo" |
然后想要在子类中覆盖
1 2 3 4 | class Foo2(Foo): @staticmethod def bar(): return"In Foo2" |
这是可行的,但是请注意,现在子类(
1 2 3 4 5 6 7 | class Foo2(Foo): @staticmethod def bar(): return"In Foo2" @staticmethod def magic(): return"Something useful you'd like to use in bar, but now can't" |
这里的解决方法是在
对我来说,这稍微违反了开/闭原则,因为在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Foo(object): @classmethod def bar(cls): return"In Foo" class Foo2(Foo): @classmethod def bar(cls): return"In Foo2" + cls.magic() @classmethod def magic(cls): return"MAGIC" print Foo2().bar() |
为:
我将试着用一个例子来解释基本的区别。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | class A(object): x = 0 def say_hi(self): pass @staticmethod def say_hi_static(): pass @classmethod def say_hi_class(cls): pass def run_self(self): self.x += 1 print self.x # outputs 1 self.say_hi() self.say_hi_static() self.say_hi_class() @staticmethod def run_static(): print A.x # outputs 0 # A.say_hi() # wrong A.say_hi_static() A.say_hi_class() @classmethod def run_class(cls): print cls.x # outputs 0 # cls.say_hi() # wrong cls.say_hi_static() cls.say_hi_class() |
我们可以直接调用静态方法和类方法,而不需要初始化
1 2 3 | # A.run_self() # wrong A.run_static() A.run_class() |
静态方法不能调用self方法,但可以调用其他静态方法和类方法
静态方法属于类,不使用对象。
类方法不绑定到对象,而是绑定到类。
@classmethod:可以用来创建对该类创建的所有实例的共享全局访问……比如由多个用户更新记录……我特别发现它在创建单例时也很有用:)
@static方法:与与…但对于可读性可以使用静态方法
我的贡献展示了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #!python3 from os import system system('cls') # % % % % % % % % % % % % % % % % % % % % class DemoClass(object): # instance methods need a class instance and # can access the instance through 'self' def instance_method_1(self): return 'called from inside the instance_method_1()' def instance_method_2(self): # an instance outside the class indirectly calls the static_method return self.static_method() + ' via instance_method_2()' # class methods don't need a class instance, they can't access the # instance (self) but they have access to the class itself via 'cls' @classmethod def class_method(cls): return 'called from inside the class_method()' # static methods don't have access to 'cls' or 'self', they work like # regular functions but belong to the class' namespace @staticmethod def static_method(): return 'called from inside the static_method()' # % % % % % % % % % % % % % % % % % % % % # works even if the class hasn't been instantiated print(DemoClass.class_method() + ' ') ''' called from inside the class_method() ''' # works even if the class hasn't been instantiated print(DemoClass.static_method() + ' ') ''' called from inside the static_method() ''' # % % % % % % % % % % % % % % % % % % % % # >>>>> all methods types can be called on a class instance <<<<< # instantiate the class democlassObj = DemoClass() # call instance_method_1() print(democlassObj.instance_method_1() + ' ') ''' called from inside the instance_method_1() ''' # # indirectly call static_method through instance_method_2(), there's really no use # for this since a @staticmethod can be called whether the class has been # instantiated or not print(democlassObj.instance_method_2() + ' ') ''' called from inside the static_method() via instance_method_2() ''' # call class_method() print(democlassObj.class_method() + ' ') ''' called from inside the class_method() ''' # call static_method() print(democlassObj.static_method()) ''' called from inside the static_method() ''' """ # whether the class is instantiated or not, this doesn't work print(DemoClass.instance_method_1() + ' ') ''' TypeError: TypeError: unbound method instancemethod() must be called with DemoClass instance as first argument (got nothing instead) ''' """ |
你可能要考虑以下的区别:
1 2 3 | Class A: def foo(): # no self parameter, no decorator pass |
和
1 2 3 4 | Class B: @staticmethod def foo(): # no self parameter pass |
这在python2和python3之间发生了变化:
python2:
1 2 3 4 5 6 | >>> A.foo() TypeError >>> A().foo() TypeError >>> B.foo() >>> B().foo() |
python3:
1 2 3 4 5 | >>> A.foo() >>> A().foo() TypeError >>> B.foo() >>> B().foo() |
因此,在python3中,只对直接从类调用的方法使用
unutbus answer已经很好地涵盖了其他情况。
类方法,顾名思义,用于修改类而不是对象。要对类进行更改,它们将修改类属性(而不是对象属性),因为这是更新类的方式。这就是类方法将类(通常用"cls"表示)作为第一个参数的原因。
1 2 3 4 5 6 | class A(object): m=54 @classmethod def class_method(cls): print"m is %d" % cls.m |
另一方面,静态方法用于执行不绑定到类的功能,即它们不会读取或写入类变量。因此,静态方法不接受类作为参数。它们的使用使得类可以执行与类的用途没有直接关系的功能。
1 2 3 4 5 6 | class X(object): m=54 #will not be referenced @staticmethod def static_method(): print"Referencing/calling a variable or function outside this class. E.g. Some global variable/function." |
分析@staticmethod提供了不同的见解。
类的普通方法是隐式动态方法,它以实例作为第一个参数。相反,staticmethod不将实例作为第一个参数,因此称为"static"。
静态方法实际上是一个与类定义之外的函数相同的普通函数。幸运的是,它被分组到类中,只是为了站得离应用程序更近一些,或者您可以滚动找到它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #!/usr/bin/python #coding:utf-8 class Demo(object): def __init__(self,x): self.x = x @classmethod def addone(self, x): return x+1 @staticmethod def addtwo(x): return x+2 def addthree(self, x): return x+3 def main(): print Demo.addone(2) print Demo.addtwo(2) #print Demo.addthree(2) #Error demo = Demo(2) print demo.addthree(2) if __name__ == '__main__': main() |
在iPython中对其他相同的方法进行快速整理后发现,
为了代码的可读性,我将避免