用@staticmethod修饰的方法和用@classmethod修饰的方法有什么区别?
当前回答
让我先告诉一下用@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',)
其他回答
顾名思义,类方法用于更改类而不是对象。要对类进行更改,它们将修改类属性(而不是对象属性),因为这就是更新类的方式。这就是类方法将类(通常用“cls”表示)作为第一个参数的原因。
class A(object):
m=54
@classmethod
def class_method(cls):
print "m is %d" % cls.m
另一方面,静态方法用于执行未绑定到类的功能,即它们不会读取或写入类变量。因此,静态方法不将类作为参数。使用它们是为了使类可以执行与类的目的不直接相关的功能。
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."
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_nonormal_instance_method。这就是所谓的“实例方法”。当使用实例方法时,它被用作部分函数(与在源代码中查看时为所有值定义的总函数相反),也就是说,当使用时,第一个参数被预定义为对象的实例及其所有给定属性。它绑定了对象的实例,并且必须从对象的实例调用它。通常,它将访问实例的各种属性。
例如,这是一个字符串的实例:
', '
如果我们使用实例方法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'
静态方法
静态方法不将实例作为参数。
它非常类似于模块级函数。
但是,模块级函数必须存在于模块中,并且必须专门导入到使用它的其他地方。
然而,如果它附加到对象,它将通过导入和继承方便地跟随对象。
静态方法的一个示例是str.maketrans,它是从Python 3中的字符串模块移动来的。它使转换表适合str.translate使用。从字符串的实例中使用它似乎很愚蠢,如下所示,但从字符串模块导入函数相当笨拙,能够从类中调用它很好,如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'
Class方法
类方法与实例方法相似,因为它接受隐式的第一个参数,但不是接受实例,而是接受类。为了更好地使用语义,它们通常被用作替代构造函数,它将支持继承。
内置类方法最典型的例子是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'>
请参阅panda源代码以了解其他类似的替代构造函数示例,也可以参阅关于classmethod和staticmethod的Python官方文档。
只有第一个参数不同:
normal方法:当前对象作为(附加)第一个参数自动传递classmethod:当前对象的类自动作为(附加的)第一个参数传递staticmethod:不会自动传递额外的参数。传递给函数的就是得到的。
更详细地说。。。
正常方法
“标准”方法,如在所有面向对象的语言中。当调用对象的方法时,会自动为其提供一个额外的参数self作为其第一个参数。即,方法
def f(self, x, y)
必须使用2个参数调用。self是自动传递的,它是对象本身。类似于这个神奇地出现在例如java/c++中,只有在python中才显式显示。
实际上,第一个参数不必称为self,但它是标准的约定,所以请保留它
类方法
装饰方法时
@classmethod
def f(cls, x, y)
自动提供的参数不是self,而是self的类。
静态法
装饰方法时
@staticmethod
def f(x, y)
该方法根本没有给出任何自动参数。它只提供调用它的参数。
用法
classmethod主要用于替代构造函数。staticmethod不使用对象的状态,甚至不使用类本身的结构。它可以是类外部的函数。它只放在类中,用于对具有类似功能的函数进行分组(例如,像Java的Math类静态方法)
class Point
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def frompolar(cls, radius, angle):
"""The `cls` argument is the `Point` class itself"""
return cls(radius * cos(angle), radius * sin(angle))
@staticmethod
def angle(x, y):
"""this could be outside the class, but we put it here
just because we think it is logically related to the class."""
return atan(y, x)
p1 = Point(3, 2)
p2 = Point.frompolar(3, pi/4)
angle = Point.angle(3, 2)
我认为一个更好的问题是“你什么时候会使用@classmethod vs@staticmethod?”
@classmethod允许您轻松访问与类定义关联的私有成员。这是一种很好的方法来实现单实例,或者控制所创建对象实例数量的工厂类。
@staticmethod提供了边际性能增益,但我还没有看到静态方法在类内的有效使用,而静态方法不能作为类外的独立函数实现。
@类方法:
可以通过cls和直接通过类名调用类变量和实例、类和静态方法,但不能通过实例变量。可以通过对象和类名直接调用。第一个参数需要cls,否则无法调用@classmethod,并且按照惯例使用cls的名称,因此其他名称而不是cls仍然有效。
@静态方法:
既可以由对象调用,也可以直接由类名调用。可以通过类名而不是实例变量直接调用类变量和实例、类和静态方法。不需要self或cls。
*在回答Python中什么是“实例方法”时,我还详细解释了实例方法?
@类方法:
例如,@classmethod可以通过cls和直接通过类名调用类变量和实例、类和静态方法,@classmethod可以通过对象和直接通过类名称调用,如下所示:
class Person:
x = "Hello"
def __init__(self, name):
self.name = name
@classmethod # Here
def test1(cls):
print(cls.x) # Class variable by `cls`
cls.test2(cls) # Instance method by `cls`
cls.test3() # Class method by `cls`
cls.test4() # Static method by `cls`
print()
print(Person.x) # Class variable by class name
Person.test2("Test2") # Instance method by class name
Person.test3() # Class method by class name
Person.test4() # Static method by class name
def test2(self):
print("Test2")
@classmethod
def test3(cls):
print("Test3")
@staticmethod
def test4():
print("Test4")
obj = Person("John")
obj.test1() # By object
# Or
Person.test1() # By class name
输出:
Hello
Test2
Test3
Test4
Hello
Test2
Test3
Test4
而且,@classmethod不能同时通过cls和直接通过类名调用实例变量,因此如果@classmethod试图同时通过cls和直接通过类名称调用实例变量(如下所示):
# ...
@classmethod
def test1(cls):
print(cls.name) # Instance variable by `cls`
# Or
print(Person.name) # Instance variable by class name
# ...
obj = Person("John")
obj.test1()
# Or
Person.test1()
出现以下错误:
AttributeError:类型对象“Person”没有属性“name”
如果@classmethod没有cls:
# ...
@classmethod
def test1(): # Without "cls"
print("Test1")
# ...
obj = Person("John")
obj.test1()
# Or
Person.test1()
@无法调用classmethod,则出现如下错误:
TypeError:test1()采用0个位置参数,但给出了1个
而且,cls的名称在约定中使用,因此其他名称而不是cls仍然有效,如下所示:
# ...
@classmethod
def test1(orange):
print(orange.x) # Class variable
orange.test2(orange) # Instance method
orange.test3() # Class method
orange.test4() # Static method
# ...
obj = Person("John")
obj.test1()
# Or
Person.test1()
输出:
Hello
Test2
Test3
Test4
@静态方法:
例如,@staticmethod既可以按对象调用,也可以按类名直接调用,如下所示:
class Person:
x = "Hello"
def __init__(self, name):
self.name = name
@staticmethod # Here
def test1():
print("Test1")
def test2(self):
print("Test2")
@classmethod
def test3(cls):
print("Test3")
@staticmethod
def test4():
print("Test4")
obj = Person("John")
obj.test1() # By object
# Or
Person.test1() # By class name
输出:
Test1
而且,@staticmethod可以通过类名直接调用类变量和实例、类和静态方法,而不是实例变量,如下所示:
# ...
@staticmethod
def test1():
print(Person.x) # Class variable
Person.test2("Test2") # Instance method
Person.test3() # Class method
Person.test4() # Static method
# ...
obj = Person("John")
obj.test1()
# Or
Person.test1()
输出:
Hello
Test2
Test3
Test4
并且,如果@staticmethod尝试调用实例变量,如下所示:
# ...
@staticmethod
def test1():
print(Person.name) # Instance variable
# ...
obj = Person("John")
obj.test1()
# Or
Person.test1()
出现以下错误:
AttributeError:类型对象“Person”没有属性“name”
而且,@staticmethod不需要self或cls,因此如果@staticmmethod具有self或cl,则需要传递如下所示的参数:
# ...
@staticmethod
def test1(self): # With "self"
print(self)
# Or
@staticmethod
def test1(cls): # With "cls"
print(cls)
# ...
obj = Person("John")
obj.test1("Test1") # With an argument
# Or
Person.test1("Test1") # With an argument
输出:
Test1
否则,如果不传递如下所示的参数:
# ...
@staticmethod
def test1(self): # With "self"
print("Test1")
# Or
@staticmethod
def test1(cls): # With "cls"
print("Test1")
# ...
obj = Person("John")
obj.test1() # Without an argument
# Or
Person.test1() # Without an argument
出现以下错误:
TypeError:test1()缺少1个必需的位置参数:“self”
TypeError:test1()缺少1个必需的位置参数:“cls”
推荐文章
- 在Python中获取大文件的MD5哈希值
- 在Python格式字符串中%s是什么意思?
- 如何循环通过所有但最后一项的列表?
- python用什么方法避免默认参数为空列表?
- ValueError: numpy。Ndarray大小改变,可能表示二进制不兼容。期望从C头得到88,从PyObject得到80
- Anaconda /conda -安装特定的软件包版本
- 我在哪里调用Keras的BatchNormalization函数?
- 打印测试执行时间并使用py.test锁定缓慢的测试
- 插入一行到熊猫数据框架
- 要列出Pandas DataFrame列
- 在Django模型中存储电话号码的最佳方法是什么?
- 从导入的模块中模拟函数
- 滚动或滑动窗口迭代器?
- python的方法找到最大值和它的索引在一个列表?
- 如何读取文件的前N行?