用@staticmethod修饰的方法和用@classmethod修饰的方法有什么区别?
当前回答
实例方法:
+可以修改对象实例状态
+可以修改类状态
类方法:
-无法修改对象实例状态
+可以修改类状态
静态方法:
-无法修改对象实例状态
-无法修改类状态
class MyClass:
'''
Instance method has a mandatory first attribute self which represent the instance itself.
Instance method must be called by a instantiated instance.
'''
def method(self):
return 'instance method called', self
'''
Class method has a mandatory first attribute cls which represent the class itself.
Class method can be called by an instance or by the class directly.
Its most common using scenario is to define a factory method.
'''
@classmethod
def class_method(cls):
return 'class method called', cls
'''
Static method doesn’t have any attributes of instances or the class.
It also can be called by an instance or by the class directly.
Its most common using scenario is to define some helper or utility functions which are closely relative to the class.
'''
@staticmethod
def static_method():
return 'static method called'
obj = MyClass()
print(obj.method())
print(obj.class_method()) # MyClass.class_method()
print(obj.static_method()) # MyClass.static_method()
输出:
('instance method called', <__main__.MyClass object at 0x100fb3940>)
('class method called', <class '__main__.MyClass'>)
static method called
实例方法实际上可以访问对象实例,所以这是我的类对象的一个实例,而使用类方法,我们可以访问类本身。但不适用于任何对象,因为类方法并不真正关心现有的对象。但是,您可以同时调用对象实例上的类方法和静态方法。这将起作用,但实际上并没有什么不同,所以当你在这里调用静态方法时,它会起作用,它会知道你要调用哪个方法。
静态方法用于执行一些实用程序任务,类方法用于工厂方法。工厂方法可以为不同的用例返回类对象。
最后,举一个简短的例子来更好地理解:
class Student:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@classmethod
def get_from_string(cls, name_string: str):
first_name, last_name = name_string.split()
if Student.validate_name(first_name) and Student.validate_name(last_name):
return cls(first_name, last_name)
else:
print('Invalid Names')
@staticmethod
def validate_name(name):
return len(name) <= 10
stackoverflow_student = Student.get_from_string('Name Surname')
print(stackoverflow_student.first_name) # Name
print(stackoverflow_student.last_name) # Surname
其他回答
我将用一个例子来解释基本的区别。
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-我们可以直接调用静态和类方法,而无需初始化
# A.run_self() # wrong
A.run_static()
A.run_class()
2-静态方法不能调用self方法,但可以调用其他静态和类方法
3-静态方法属于类,根本不会使用对象。
4-类方法不绑定到对象,而是绑定到类。
我认为一个更好的问题是“你什么时候会使用@classmethod vs@staticmethod?”
@classmethod允许您轻松访问与类定义关联的私有成员。这是一种很好的方法来实现单实例,或者控制所创建对象实例数量的工厂类。
@staticmethod提供了边际性能增益,但我还没有看到静态方法在类内的有效使用,而静态方法不能作为类外的独立函数实现。
@python2.4中添加了修饰符。如果您使用的是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)
还要注意,这是一个使用类方法和静态方法的好例子,静态方法显然属于类,因为它在内部使用了类Cluster。类方法只需要关于类的信息,而不需要对象的实例。
将_is_cluster_for方法设置为类方法的另一个好处是,子类可以决定更改其实现,这可能是因为它非常通用,可以处理多种类型的集群,因此仅检查类的名称是不够的。
静态方法:
没有自参数的简单函数。处理类属性;而不是实例属性。可以通过类和实例调用。内置函数staticmethod()用于创建它们。
静态方法的优点:
它在类作用域中本地化函数名它将功能代码移动到使用位置附近与模块级函数相比,导入更方便,因为不必专门导入每个方法@静态方法定义some_static_method(*args,**kwds):通过
类方法:
将第一个参数作为类名的函数。可以通过类和实例调用。这些是用内置函数中的classmethod创建的。@分类法定义some_class_method(cls,*args,**kwds):通过
关于staticmethod vs classmethod的另一个考虑是继承。假设你有以下课程:
class Foo(object):
@staticmethod
def bar():
return "In Foo"
然后您需要在子类中重写bar():
class Foo2(Foo):
@staticmethod
def bar():
return "In Foo2"
这是可行的,但请注意,现在子类(Foo2)中的bar()实现不能再利用该类特有的任何特性。例如,假设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"
这里的解决方法是在bar()中调用Foo2.magic(),但随后您重复自己的操作(如果Foo2的名称发生更改,您必须记住更新bar()方法)。
对我来说,这稍微违反了开放/封闭原则,因为在Foo中做出的决定会影响您重构派生类中的公共代码的能力(即扩展的开放性较低)。如果bar()是一个类方法,我们就可以了:
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
此外:历史笔记:Guido Van Rossum(Python的创建者)曾将静态方法称为“意外”:https://mail.python.org/pipermail/python-ideas/2012-May/014969.html
我们都知道静态方法有多有限。(它们基本上是一个意外——回到Python 2.2时代,当我发明新型类和描述符时,我想实现类方法,但一开始我不理解它们,意外地先实现了静态方法。然后,删除它们,只提供类方法已经太晚了。
也:https://mail.python.org/pipermail/python-ideas/2016-July/041189.html
老实说,staticmethod是一个错误——我试图做一些类似Java类方法的事情,但一旦发布,我发现真正需要的是类方法。但要摆脱静态方法为时已晚。
推荐文章
- 使用散射数据集生成热图
- python:将脚本工作目录更改为脚本自己的目录
- 如何以编程方式获取python.exe位置?
- 如何跳过循环中的迭代?
- 使用Pandas为字符串列中的每个值添加字符串前缀
- ImportError:没有名为matplotlib.pyplot的模块
- 在python中遍历对象属性
- 如何在Python中使用方法重载?
- 在Python中提取文件路径(目录)的一部分
- 将类代码分离为头文件和cpp文件
- 如何安装没有根访问权限的python模块?
- 尝试模拟datetime.date.today(),但不工作
- 在PHP中使用getter和setter而不是函数或简单的公共字段有什么优点?
- 将行添加到数组
- 如何在Python中直接获得字典键作为变量(而不是通过从值搜索)?