装饰的功能有什么区别 @staticmethod
一个装饰着 @classmethod
?
装饰的功能有什么区别 @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(<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)
人们发现用于类方法的一个用途是创建 可继承的替代构造函数。
使用staticmethods,都没有 self
(对象实例)也没有 cls
(类)隐式传递为第一个参数。它们的行为类似于普通函数,除了您可以从实例或类中调用它们:
a.static_foo(1)
# executing static_foo(1)
A.static_foo('hi')
# executing static_foo(hi)
Staticmethod用于将与类有逻辑连接的函数分组到类中。
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
也期待一个论点。
print(a.static_foo)
# <function static_foo at 0xb7d479cc>
当然,当你打电话时也会发生同样的事情 static_foo
与班级 A
代替。
print(A.static_foo)
# <function static_foo at 0xb7d479cc>
一个 静态方法 是一种对调用它的类或实例一无所知的方法。它只是获取传递的参数,没有隐含的第一个参数。它在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文档:
类方法接收类为 隐含的第一个参数,就像一个 instance方法接收实例。 要声明一个类方法,请使用它 成语:
class C: @classmethod def f(cls, arg1, arg2, ...): ...
该
@classmethod
形式是一种功能 装饰 - 见描述 函数定义 功能 定义 详情。它可以在课堂上调用 (如
C.f()
)或在一个实例上 (如C().f()
)。实例是 被忽略了除了它的类。如果一个 为派生调用类方法 class,派生类对象是 作为隐含的第一个参数传递。类方法与C ++不同 或Java静态方法。如果你想 那些,看
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
在这个字符串上,加入另一个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)
<class '__main__.MyDict'>
见 熊猫源代码 有关替代构造函数的其他类似示例,另请参阅官方Python文档 classmethod
和 staticmethod
。
在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
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)
<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'>