用@staticmethod修饰的方法和用@classmethod修饰的方法有什么区别?
当前回答
当存在继承时,就会出现差异。
假设有两个类——父类和子类。如果要使用@staticmethod,print_name方法应该写两次,因为类的名称应该写在打印行中。
class Parent:
_class_name = "Parent"
@staticmethod
def print_name():
print(Parent._class_name)
class Child(Parent):
_class_name = "Child"
@staticmethod
def print_name():
print(Child._class_name)
Parent.print_name()
Child.print_name()
但是,对于@classmethod,不需要编写print_name方法两次。
class Parent:
_class_name = "Parent"
@classmethod
def print_name(cls):
print(cls._class_name)
class Child(Parent):
_class_name = "Child"
Parent.print_name()
Child.print_name()
其他回答
Python带有几个内置的装饰器。三大类是:
@classmethod
@staticmethod
@property
首先,让我们注意,类的任何函数都可以用这个类的实例调用(在初始化这个类之后)。
@classmethod是一种方法,它不仅可以作为类的实例调用函数,还可以直接由类本身作为其第一个参数调用函数。
@staticmethod是一种将函数放入类的方法(因为它在逻辑上属于类),同时表示它不需要访问类(因此我们不需要在函数定义中使用self)。
让我们考虑一下以下课程:
class DecoratorTest(object):
def __init__(self):
pass
def doubler(self, x):
return x*2
@classmethod
def class_doubler(cls, x): # we need to use 'cls' instead of 'self'; 'cls' reference to the class instead of an instance of the class
return x*2
@staticmethod
def static_doubler(x): # no need adding 'self' here; static_doubler() could be just a function not inside the class
return x*2
让我们看看它是如何工作的:
decor = DecoratorTest()
print(decor.doubler(5))
# 10
print(decor.class_doubler(5)) # a call with an instance of a class
# 10
print(DecoratorTest.class_doubler(5)) # a direct call by the class itself
# 10
# staticmethod could be called in the same way as classmethod.
print(decor.static_doubler(5)) # as an instance of the class
# 10
print(DecoratorTest.static_doubler(5)) # or as a direct call
# 10
这里您可以看到这些方法的一些用例。
奖金:您可以在这里阅读@property decorator
对iPython中其他相同方法的快速破解表明,@staticmethod产生了边际性能增益(以纳秒为单位),但在其他方面它似乎没有任何作用。此外,在编译过程中通过staticmethod()处理方法的额外工作(这在运行脚本时任何代码执行之前发生)可能会抵消任何性能提升。
为了代码的可读性,我会避免@staticmethod,除非您的方法将用于纳秒计数的工作量。
我认为提供一个纯Python版本的staticmethod和classmethod将有助于在语言级别上理解它们之间的区别(请参阅Descriptor Howto Guide)。
这两个都是非数据描述符(如果您首先熟悉描述符,那么更容易理解它们)。
class StaticMethod(object):
"Emulate PyStaticMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
def __get__(self, obj, objtype=None):
return self.f
class ClassMethod(object):
"Emulate PyClassMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
def __get__(self, obj, cls=None):
def inner(*args, **kwargs):
if cls is None:
cls = type(obj)
return self.f(cls, *args, **kwargs)
return inner
@类方法:
可以通过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”
让我先告诉一下用@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',)
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用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中获得所有直接子目录