用@staticmethod修饰的方法和用@classmethod修饰的方法有什么区别?
当前回答
也许一些示例代码会有所帮助:注意foo、class_foo和static_foo的调用签名的不同:
class A(object):
def foo(self, x):
print(f"executing foo({self}, {x})")
@classmethod
def class_foo(cls, x):
print(f"executing class_foo({cls}, {x})")
@staticmethod
def static_foo(x):
print(f"executing static_foo({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)
静态方法用于将与类有某种逻辑联系的函数分组到该类。
foo只是一个函数,但当你调用.foo时,你不只是得到函数,您将得到函数的“部分应用”版本,其中对象实例a作为函数的第一个参数。foo需要2个参数,而a.foo只需要1个参数。
a绑定到foo。这就是以下术语“约束”的含义:
print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
对于.class_foo,a不绑定到class_foo,而类a绑定到class-foo。
print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>
这里,对于staticmethod,即使它是一个方法,a.static_foo也只返回一个没有参数约束的好的ole函数。static_foo需要1个参数,并且.static_foo也需要1个参数。
print(a.static_foo)
# <function static_foo at 0xb7d479cc>
当然,当用类A调用static_foo时也会发生同样的情况。
print(A.static_foo)
# <function static_foo at 0xb7d479cc>
其他回答
也许一些示例代码会有所帮助:注意foo、class_foo和static_foo的调用签名的不同:
class A(object):
def foo(self, x):
print(f"executing foo({self}, {x})")
@classmethod
def class_foo(cls, x):
print(f"executing class_foo({cls}, {x})")
@staticmethod
def static_foo(x):
print(f"executing static_foo({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)
静态方法用于将与类有某种逻辑联系的函数分组到该类。
foo只是一个函数,但当你调用.foo时,你不只是得到函数,您将得到函数的“部分应用”版本,其中对象实例a作为函数的第一个参数。foo需要2个参数,而a.foo只需要1个参数。
a绑定到foo。这就是以下术语“约束”的含义:
print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
对于.class_foo,a不绑定到class_foo,而类a绑定到class-foo。
print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>
这里,对于staticmethod,即使它是一个方法,a.static_foo也只返回一个没有参数约束的好的ole函数。static_foo需要1个参数,并且.static_foo也需要1个参数。
print(a.static_foo)
# <function static_foo at 0xb7d479cc>
当然,当用类A调用static_foo时也会发生同样的情况。
print(A.static_foo)
# <function static_foo at 0xb7d479cc>
这是一篇关于这个问题的短文
@staticmethod函数只不过是在类中定义的函数。它可以在不首先实例化类的情况下调用。它的定义通过继承是不可变的。@classmethod函数也可以在不实例化类的情况下调用,但它的定义通过继承遵循子类,而不是父类。这是因为@classmethod函数的第一个参数必须始终是cls(class)。
太长,读不下去了
静态方法本质上是绑定到类(及其实例)的函数
类方法本质上是一种可继承的静态方法。
有关详细信息,请参阅其他人的优秀答案。
@类方法:
可以通过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中基本上是无用的——您可以只使用模块函数而不是静态方法。
另一方面,类方法是一种方法,它将被调用的类或被调用的实例的类作为第一个参数传递。当您希望该方法成为类的工厂时,这很有用:因为它获得了作为第一个参数调用的实际类,所以即使涉及子类,您也可以始终实例化正确的类。例如,观察类方法dict.fromkeys()在子类上调用时如何返回子类的实例:
>>> class DictSubclass(dict):
... def __repr__(self):
... return "DictSubclass"
...
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>>
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录