装饰的功能@staticmethod
和装饰的功能有什么区别@classmethod
?
也许一些示例代码会有所帮助:注意调用签名的区别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(,1)
您也可以class_foo
使用该课程进行呼叫.实际上,如果你将某些东西定义为类方法,那可能是因为你打算从类而不是类实例中调用它.A.foo(1)
会产生一个TypeError,但A.class_foo(1)
工作得很好:
A.class_foo(1) # executing class_foo(,1)
人们发现类方法的一个用途是创建可继承的替代构造函数.
使用staticmethods时,self
(对象实例)和cls
(类)都不会 作为第一个参数隐式传递.它们的行为类似于普通函数,除了您可以从实例或类中调用它们:
a.static_foo(1) # executing static_foo(1) A.static_foo('hi') # executing static_foo(hi)
Staticmethods用于将与类具有某种逻辑连接的函数分组到类中.
foo
只是一个函数,但是当你调用时a.foo
不仅仅是获取函数,你得到函数的"部分应用"版本,并将对象实例a
绑定为函数的第一个参数.foo
期望2个参数,而a.foo
只需要1个参数.
a
必然会foo
.这就是下面"绑定"一词的含义:
print(a.foo) #>
用a.class_foo
,a
不是必然的class_foo
,而是类A
必然class_foo
.
print(a.class_foo) #>
在这里,使用static方法,即使它是一个方法,a.static_foo
只返回一个没有参数绑定的良好'ole函数.static_foo
期望1个参数,并且也
a.static_foo
期望1个参数.
print(a.static_foo) #
当然,当您static_foo
与班级打电话时会发生同样的事情A
.
print(A.static_foo) #
一个静态方法是一无所知,它被称为上类或实例的方法.它只是获取传递的参数,没有隐含的第一个参数.它在Python中基本没用 - 您可以使用模块函数而不是静态方法.
甲类方法,在另一方面,是获取传递的类,它被称为上,或该类的实例,它被称为上的,作为第一个参数的方法.当你希望方法成为类的工厂时,这很有用:因为它获得了作为第一个参数调用的实际类,所以即使涉及子类,也可以始终实例化正确的类.例如dict.fromkeys()
,观察一个classmethod 如何在子类上调用时返回子类的实例:
>>> class DictSubclass(dict): ... def __repr__(self): ... return "DictSubclass" ... >>> dict.fromkeys("abc") {'a': None, 'c': None, 'b': None} >>> DictSubclass.fromkeys("abc") DictSubclass >>>
基本上@classmethod
创建一个方法,其第一个参数是从中调用的类(而不是类实例),@staticmethod
没有任何隐式参数.
官方python文档:
@classmethod
类方法接收类作为隐式的第一个参数,就像实例方法接收实例一样.要声明一个类方法,请使用此成语:
class C: @classmethod def f(cls, arg1, arg2, ...): ...该
@classmethod
形式是一个函数 装饰 -见的功能定义描述函数定义的细节.它可以在类(例如
C.f()
)或实例(例如C().f()
)上调用.除了类之外,该实例被忽略.如果为派生类调用类方法,则派生类对象将作为隐含的第一个参数传递.类方法与C++或Java静态方法不同.如果您需要,请参阅
staticmethod()
本节.
@staticmethod
静态方法不会接收隐式的第一个参数.要声明静态方法,请使用此惯用法:
class C: @staticmethod def f(arg1, arg2, ...): ...该
@staticmethod
形式是一个函数 装饰 -见的功能定义描述函数定义的细节.它可以在类(例如
C.f()
)或实例(例如C().f()
)上调用.除了类之外,该实例被忽略.Python中的静态方法与Java或C++中的静态方法类似.有关更高级的概念,请参阅
classmethod()
本节.
这是一篇关于这个问题的简短文章
@staticmethod函数只不过是在类中定义的函数.它可以在不首先实例化类的情况下调用.它的定义是通过继承不可变的.
@classmethod函数也可以在不实例化类的情况下调用,但它的定义遵循Sub类,而不是Parent类,通过继承.那是因为@classmethod函数的第一个参数必须始终是cls(class).
要决定是否使用@staticmethod或@classmethod,你必须查看你的方法.如果您的方法访问类中的其他变量/方法,则使用@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中的@staticmethod和@classmethod有什么区别?
你可能已经看过像这个伪代码的Python代码,它演示了各种方法类型的签名,并提供了一个文档字符串来解释每个:
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
.这恰恰称为" 实例方法 ".当使用实例方法时,它被用作部分函数(与在源代码中查看时为所有值定义的总函数相对),即,当使用时,第一个参数被预定义为实例.对象,具有所有给定的属性.它具有绑定到它的对象的实例,并且必须从对象的实例调用它.通常,它将访问实例的各种属性.
例如,这是一个字符串的实例:
', '
如果我们join
在这个字符串上使用instance方法来连接另一个iterable,那么它显然是实例的一个函数,除了是可迭代列表的函数之外['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'静态方法
静态方法并没有把实例作为参数.
它与模块级功能非常相似.
但是,模块级功能必须存在于模块中并专门导入到使用它的其他位置.
但是,如果它附加到对象,它也将通过导入和继承方便地跟随对象.
静态方法的一个示例是str.maketrans
从string
Python 3中的模块移动.它使转换表适合于使用str.translate
.从字符串实例中使用时看起来确实相当愚蠢,如下所示,但从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中,您必须从越来越不实用的字符串模块中导入此函数:
>>> import string >>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc')) 'abcDEFG'类方法
类方法类似于实例方法,因为它采用隐式的第一个参数,但不是采用实例,而是采用类.通常这些用作替代构造函数以获得更好的语义用法,并且它将支持继承.
内置类方法的最典型示例是dict.fromkeys
.它被用作dict的替代构造函数(非常适合当你知道你的键是什么并且想要它们的默认值时.)
>>> dict.fromkeys(['a', 'b', 'c']) {'c': None, 'b': None, 'a': None}
当我们继承dict时,我们可以使用相同的构造函数,它创建子类的实例.
>>> 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)
有关替代构造函数的其他类似示例,请参阅pandas源代码,另请参阅有关classmethod
和的官方Python文档staticmethod
.
我开始用C++学习编程语言,然后是Java,然后是Python,所以这个问题也困扰了我,直到我理解了每个的简单用法.
类方法: Python与Java不同,C++没有构造函数重载.所以要实现这一点,你可以使用classmethod
.下面的例子将解释这一点
让我们考虑,我们有一个Person
类,它有两个参数first_name
与last_name
和创建人的实例.
class Person(object): def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name
现在,如果需要只使用一个名称创建一个类,只需要一个Person
,你就不能在python中做这样的事情了.
当您尝试创建对象(实例)时,这将给您一个错误.
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
但是,你可以使用first_name
下面提到的相同的东西
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, "")
静态方法::这很简单,它没有绑定到实例或类,您只需使用类名称调用它.
因此,在上面的示例中,您需要一个@classmethod
不超过20个字符的验证,您可以简单地执行此操作.
@staticmethod def validate_name(name): return len(name) <= 20
你可以简单地使用Class Name调用
Person.validate_name("Gaurang Shah")
在Python 2.4中添加了@decorators如果您使用的是python <2.4,则可以使用classmethod()和staticmethod()函数.
例如,如果要创建工厂方法(一个函数根据它获取的参数返回类的不同实现的实例),您可以执行以下操作:
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和静态方法的一个很好的例子.静态方法显然属于类,因为它在内部使用类Cluster.classmethod只需要有关类的信息,而不需要对象的实例.
制作的另一个好处_is_cluster_for
方法一类方法是这样子类可以决定改变它的实现,也许是因为它是非常通用的,可以处理多种类型的集群,所以只检查类的名称是不够的.
我认为一个更好的问题是"你什么时候使用@classmethod vs @staticmethod?"
@classmethod允许您轻松访问与类定义关联的私有成员.这是做单例的好方法,或者是控制所创建对象的实例数的工厂类.
@staticmethod提供了边际性能提升,但我还没有看到类中的静态方法的有效使用,这种方法无法作为类外的独立函数实现.
静态方法:
简单的函数,没有自我论证.
处理类属性; 不是实例属性.
可以通过类和实例调用.
内置函数staticmethod()用于创建它们.
静态方法的好处:
它在classscope中本地化函数名称
它将功能代码移动到更接近使用位置的位置
导入和模块级函数更方便,因为不必专门导入每种方法
@staticmethod def some_static_method(*args, **kwds): pass
分类方法:
具有第一个参数作为类名的函数.
可以通过类和实例调用.
这些是使用classmethod内置函数创建的.
@classmethod def some_class_method(cls, *args, **kwds): pass
@staticmethod
只是禁用默认函数作为方法描述符.classmethod将您的函数包装在一个可调用的容器中,该容器将对所属类的引用作为第一个参数传递:
>>> class C(object): ... pass ... >>> def f(): ... pass ... >>> staticmethod(f).__get__(None, C)>>> classmethod(f).__get__(None, C) >
事实上,classmethod
它具有运行时开销,但可以访问拥有的类.或者,我建议使用元类并将类方法放在该元类上:
>>> class CMeta(type): ... def foo(cls): ... print cls ... >>> class C(object): ... __metaclass__ = CMeta ... >>> C.foo()
关于如何在Python中使用静态,类或抽象方法的权威指南是本主题的一个很好的链接,并总结如下.
@staticmethod
函数只不过是在类中定义的函数.它可以在不首先实例化类的情况下调用.它的定义是通过继承不可变的.
Python不必实例化对象的绑定方法.
它简化了代码的可读性,并且它不依赖于对象本身的状态;
@classmethod
函数也可以在不实例化类的情况下调用,但是它的定义遵循Sub类,而不是Parent类,通过继承,可以被子类覆盖.那是因为@classmethod
函数的第一个参数必须始终是cls(class).
工厂方法,用于为类创建实例,例如使用某种预处理.
调用静态方法的静态方法:如果在多个静态方法中拆分静态方法,则不应对类名进行硬编码,而应使用类方法
让我先说一下用@classmethod和@staticmethod修饰的方法之间的相似性.
相似性:它们都可以在类本身上调用,而不仅仅是类的实例.因此,它们在某种意义上都是Class的方法.
差异:类方法将接收类本身作为第一个参数,而静态方法则不接受.
因此,静态方法在某种意义上并不局限于类本身,只是因为它可能具有相关功能而挂在那里.
>>> 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',)
关于staticmethod vs classmethod的另一个考虑因素是继承.假设您有以下课程:
class Foo(object): @staticmethod def bar(): return "In Foo"
然后你想要bar()
在子类中重写:
class Foo2(Foo): @staticmethod def bar(): return "In Foo2"
这有效,但请注意,现在bar()
子类(Foo2
)中的实现无法再利用该类特定的任何内容.例如,假设Foo2
有一个名为magic()
你想要在Foo2
执行中使用的方法bar()
:
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"
这里的解决办法是打电话Foo2.magic()
的bar()
,但此时你重复自己(如果名称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
第一个参数不同:
普通方法:第一个参数是(自动)当前对象
classmethod:第一个参数是(自动)当前对象的类
staticmethod:第一个参数不会自动传递
更详细地...
调用对象的方法时,它会自动获得一个额外的参数self
作为其第一个参数。即方法
def f(self, x, y)
必须使用2个参数调用。self
是自动传递的,它是对象本身。
装饰方法时
@classmethod def f(cls, x, y)
自动提供的参数不是 self
,而是的类 self
。
装饰方法时
@staticmethod def f(x, y)
该方法根本没有任何自动参数。仅提供调用它的参数。
用法
classmethod
主要用于替代构造函数。
staticmethod
不使用对象的状态。它可能是类外部的函数。它仅放在类中以对具有相似功能的函数进行分组(例如,类似于Java的Math
类静态方法)
def f(self, x, y)
我将尝试使用示例来解释基本差异.
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 - 我们可以直接调用static和classmethods而无需初始化
# A.run_self() # wrong A.run_static() A.run_class()
2-静态方法不能调用self方法但可以调用其他静态方法和class方法
3-静态方法属于类,根本不使用对象.
4-类方法不是绑定到对象而是绑定到类.
@classmethod:可用于创建对该类创建的所有实例的共享全局访问.....就像由多个用户更新记录...。我特别发现它在创建单例时也非常有用。 )
@static方法:与与...相关联的类或实例无关,但出于可读性考虑,可以使用static方法