Python中的@staticmethod和@classmethod有什么区别?
用@staticmethod
装饰的function和用@staticmethod
装饰的function有@staticmethod
@classmethod
?
也许有一些示例代码会有帮助:注意foo
, class_foo
和static_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)"%xa=A()
以下是对象实例调用方法的常用方法。 对象实例a
隐式地作为第一个parameter passing。
a.foo(1) # executing foo(<__main__.A object at 0xb7dbef0c>,1)
在类方法中 ,对象实例的类作为第一个参数隐式传递,而不是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)
一个人使用的方法是创build可inheritance的替代构造函数 。
使用静态方法 , self
(对象实例)和cls
(类)都不会作为第一个参数隐式传递。 除了可以从实例或类调用它们之外,它们的行为与普通函数类似:
a.static_foo(1) # executing static_foo(1) A.static_foo('hi') # executing static_foo(hi)
静态方法用于对与类具有某种逻辑连接的函数进行分组。
foo
只是一个函数,但是当你调用a.foo
你不会得到这个函数,你会得到一个“部分应用”的函数版本,其中的对象实例绑定为函数的第一个参数。 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
时, static_foo
发生同样的事情。
print(A.static_foo) # <function static_foo at 0xb7d479cc>
静态方法是一种对所调用的类或实例一无所知的方法。 它只是获得通过的参数,没有隐含的第一个参数。 在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
创build了一个方法,其第一个参数是从其调用的类(而不是类实例), @staticmethod
没有任何隐式参数。
官方的python文档:
@classmethod
类方法将类作为隐式第一个参数接收,就像实例方法接收实例一样。 要声明一个类的方法,使用这个习惯用法:
class C: @classmethod def f(cls, arg1, arg2, ...): ...
@classmethod
forms是一个函数装饰器 – 有关详细信息,请参阅函数定义中的函数定义的描述。它可以在类(如
Cf()
)或实例(如C().f()
)上调用。 该实例被忽略,除了它的类。 如果为派生类调用类方法,则派生类对象作为隐含的第一个parameter passing。类方法不同于C ++或Java静态方法。 如果您需要这些,请参阅本节中的
staticmethod()
。
@staticmethod
静态方法不会收到隐式的第一个参数。 为了声明一个静态方法,使用这个习惯用法:
class C: @staticmethod def f(arg1, arg2, ...): ...
@staticmethod
forms是一个函数装饰器 – 详细信息请参阅函数定义中函数定义的描述。它可以在类(如
Cf()
)或实例(如C().f()
)上调用。 该实例被忽略,除了它的类。Python中的静态方法类似于Java或C ++中的方法。 有关更高级的概念,请参阅本节中的
classmethod()
。
这是关于这个问题的简短文章
@staticmethod函数不过是一个类中定义的函数。 它可以被调用,而不需要先实例化类。 它的定义是通过inheritance而不可变的。
@classmethod函数也可以在没有实例化类的情况下调用,但是其定义如下Sub类,而不是Parent类,通过inheritance。 这是因为@classmethod函数的第一个参数必须始终是cls(class)。
Python中的@staticmethod和@classmethod有什么区别?
您可能已经看到了类似于这种伪代码的Python代码,它演示了各种方法types的签名,并提供了一个文档string来解释每种方法:
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. '''
正常实例方法
首先我将解释a_normal_instance_method
。 这正是所谓的“ 实例方法 ”。 当使用实例方法时,它被用作部分函数(相对于在源代码中查看所有值时定义的全部函数),即在使用时,第一个参数被预定义为对象,具有所有的给定属性。 它具有绑定到它的对象的实例,它必须从对象的一个实例中调用。 通常,它将访问实例的各种属性。
例如,这是一个string的实例:
', '
如果我们使用实例方法, join
这个string,join另一个迭代,它显然是实例的一个函数,除了作为可迭代列表的函数之外, ['a', 'b', 'c']
:
>>> ', '.join(['a', 'b', 'c']) 'a, b, c'
绑定的方法
实例方法可以通过虚线查找来绑定以备后用。
例如,这将str.join
方法绑定到':'
实例:
>>> join_with_colons = ':'.join
后来我们可以使用它作为一个已经绑定了第一个参数的函数。 这样,就像实例上的部分函数一样工作:
>>> join_with_colons('abcde') 'a:b:c:d:e' >>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF']) 'FF:FF:FF:FF:FF:FF'
静态方法
静态方法不会将实例作为参数。
这与模块级function非常相似。
但是,模块级function必须存在于模块中,并专门导入到其他使用模块的地方。
但是,如果附加到对象上,它将通过导入和inheritance方便地跟踪对象。
静态方法的一个例子是str.maketrans
,它是从Python 3的string
模块中移出来的。它使得转换表适合str.translate
。 从string的实例中使用它似乎相当愚蠢,如下所示,但是从string
模块中导入函数相当笨拙,能够从类中调用它是很好的,就像在str.maketrans
# 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}
在Python 2中,你必须从越来越less用的string模块中导入这个函数:
>>> import string >>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc')) 'abcDEFG'
类方法
一个类方法类似于一个实例方法,因为它需要一个隐含的第一个参数,而不是采取实例,它采用类。 通常这些被用作更好的语义用法的替代构造函数,它将支持inheritance。
内置类方法的最典型的例子是dict.fromkeys
。 它被用作字典的替代构造函数,(非常适合当你知道你的键是什么,并希望他们的默认值。)
>>> dict.fromkeys(['a', 'b', 'c']) {'c': None, 'b': None, 'a': None}
当我们inheritancedict的时候,我们可以使用相同的构造函数来创build子类的一个实例。
>>> 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'>
查看其他类似的替代构造函数的pandas源代码 ,另请参阅classmethod
和staticmethod
的官方Python文档。
要决定是否使用@staticmethod或@classmethod你必须看看你的方法。 如果你的方法访问你的类中的其他variables/方法,那么使用@classmethod 。 另一方面,如果你的方法不触及类的任何其他部分,那么使用@staticmethod。
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
python 2.4中添加了@decorators如果你使用python <2.4,你可以使用classmethod()和staticmethod()函数。
例如,如果你想创build一个工厂方法(一个函数根据它得到的参数返回一个不同实现类的实例),你可以做如下的事情:
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)
还要注意,这是使用类方法和静态方法的一个很好的例子,静态方法显然属于类,因为它在内部使用类Cluster。 classmethod只需要关于类的信息,而不需要对象的实例。
使_is_cluster_for
方法成为类方法的另一个好处是,子类可以决定改变它的实现,也许因为它是非常通用的,并且可以处理多种types的集群,所以仅仅检查类的名称是不够的。
我认为一个更好的问题是“什么时候使用@classmethod和@staticmethod?”
@classmethod允许您轻松访问与类定义关联的私有成员。 这是一个很好的方式来做singletons,或工厂类,控制创build的对象的实例的数量存在。
@staticmethod提供了边际性能的提升,但是我还没有看到在类中静态方法的有效使用,而这种方法不能作为类之外的独立函数来实现。
静态方法:
- 简单的function,没有自我的论点。
- 处理class级属性; 而不是实例属性。
- 可以通过类和实例调用。
- 内置函数staticmethod()用于创build它们。
静态方法的好处:
- 它在classscope中本地化函数名称
- 它将函数代码更靠近它所使用的位置
-
导入与模块级函数更方便,因为每种方法都不需要特别导入
@staticmethod def some_static_method(*args, **kwds): pass
类方法:
- 具有第一个参数作为classname的函数。
- 可以通过类和实例调用。
-
这些是使用classmethod内置函数创build的。
@classmethod def some_class_method(cls, *args, **kwds): pass
@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'>
@classmethod的意思是 :当这个方法被调用的时候,我们传递这个类作为第一个参数,而不是那个类的实例(就像我们通常用的方法一样)。 这意味着您可以在该方法内使用该类及其属性,而不是特定的实例。
@staticmethod的意思是:当这个方法被调用的时候,我们不会把类的实例传递给它(就像我们通常用的方法一样)。 这意味着你可以在一个类中放置一个函数,但是你不能访问那个类的实例(当你的方法不使用实例的时候,这是很有用的)。
关于如何在Python中使用静态,类或抽象方法的权威指南是这个主题的一个很好的链接,并将其总结如下。
@staticmethod
函数不过是一个类中定义的函数。 它可以被调用,而不需要先实例化类。 它的定义是通过inheritance而不可变的。
- Python不必为对象实例化绑定方法。
- 它简化了代码的可读性,并且不依赖于对象本身的状态;
@classmethod
函数也可以在没有实例化类的情况下调用,但是它的定义如下Sub类,而不是Parent类,通过inheritance,可以被子类覆盖。 这是因为@classmethod
函数的第一个参数必须始终是cls (class)。
- 工厂方法 ,用于使用例如某种预处理来为类创build实例。
- 调用静态方法的静态方法 :如果在多个静态方法中分离静态方法,则不应该对类名称进行硬编码,而应使用类方法
关于静态方法和类方法的另一个考虑就是inheritance。 假设你有以下课程:
class Foo(object): @staticmethod def bar(): return "In Foo"
然后你想在一个子类中覆盖bar()
:
class Foo2(Foo): @staticmethod def bar(): return "In Foo2"
这是有效的,但是请注意,现在,子类( Foo2
)中的bar()
实现不能再利用该类的任何特定的优势。 例如,假设Foo2
有一个名为magic()
的方法,您可以在bar()
的Foo2
实现中使用它:
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"
这里的解决方法是在bar()
调用Foo2.magic()
,但是你重复自己(如果Foo2
的名字改变了,你必须记得更新bar()
方法)。
对我来说,这是一个轻微的违反开放/封闭的原则 ,因为在Foo
做出的决定影响了你在派生类中重构通用代码的能力(也就是说对扩展的开放性较低)。 如果bar()
是一个classmethod
我们会很好:
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()
给: In Foo2 MAGIC
在Python中 ,classmethod接收一个类作为隐式的第一个参数。 对象实例的类作为第一个参数隐式传递。 当需要方法作为类的工厂时,这可能是有用的,因为它将实际的类(称为方法)作为第一个参数,可以实例化正确的类,即使子类也是关心的。
静态方法只是一个类中定义的函数。 它不知道被调用的类或实例的任何内容,只获取没有任何隐含的第一个parameter passing的参数。 例:
class Test(object): def foo(self, a): print "testing (%s,%s)"%(self,a) @classmethod def foo_classmethod(cls, a): print "testing foo_classmethod(%s,%s)"%(cls,a) @staticmethod def foo_staticmethod(a): print "testing foo_staticmethod(%s)"%a test = Test()
静态方法用于将与类具有某种逻辑连接的函数分组。
我将尝试用一个例子来解释基本的差异。
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 Ax # 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 – 我们可以直接调用静态和类方法而不需要初始化
# A.run_self() # wrong A.run_static() A.run_class()
2-静态方法不能调用自己的方法,但可以调用其他静态方法和类方法
3-静态方法属于类,根本不使用对象。
4-类方法不绑定到一个对象,而是一个类。
@classmethod:可以用来创build一个共享的全局访问所有创build该类的实例…..就像更新一个logging由多个用户….我特别发现它用于创build单身人士以及..: )
@静态方法:与类或实例关联…无关,但为了可读性可以使用静态方法
我开始用C ++,然后是Java,然后是Python学习编程语言,所以这个问题困扰了我很多,直到我明白每个的简单用法。
类方法:与Java和C ++不同,Python没有构造函数重载。 为了达到这个目的,你可以使用classmethod
。 下面的例子将解释这一点
让我们考虑我们有一个Person
类,它带有两个参数first_name
和last_name
并创buildPerson的实例。
class Person(object): def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name
现在,如果需求到了需要使用单一名称创build类的地方,只需要一个first_name
。 你不能在Python中做这样的事情。
当你尝试创build一个对象(实例)时,这会给你一个错误。
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
但是,您可以使用@classmethod
来达到同样的@classmethod
,如下所述
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, "")
静态方法:这是一个相当简单的,它不绑定到实例或类,你可以使用类名简单的调用。
所以我们假设在上面的例子中,你需要validationfirst_name
不能超过20个字符,你可以简单的做到这一点。
@staticmethod def validate_name(name):return len(name)<= 20
你可以使用类名简单的调用
Person.validate_name("Gaurang Shah")
#!/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中其他相同方法的快速破解揭示了@staticmethod
产生的边际性能增益(以纳秒为单位),否则它似乎不起作用。 另外,在编译期间(在运行脚本之前执行任何代码之前staticmethod()
,通过staticmethod()
处理方法的额外工作可能会消除任何性能增益。
为了代码的可读性,我会避免@staticmethod
除非你的方法将被用于纳秒计数的工作负载。