用@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',)
其他回答
@classmethod:可用于创建对该类创建的所有实例的共享全局访问。。。。。比如由多个用户更新记录。。。。我特别发现它在创建单件时也很有用。:)
@静态方法:与关联的类或实例无关。。。但为了可读性,可以使用静态方法
我将用一个例子来解释基本的区别。
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提供了边际性能增益,但我还没有看到静态方法在类内的有效使用,而静态方法不能作为类外的独立函数实现。
关于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官方文档:
@分类法
类方法将类作为隐式第一个参数,就像instance方法接收该实例。要声明类方法,请使用成语:C类:@分类法定义f(cls,arg1,arg2,…):。。。@classmethod表单是一个函数decorator–请参见函数中的函数定义详细定义。它可以在类上调用(例如C.f())或实例(例如C().f())。实例是除了它的类之外,都被忽略。如果类方法用于派生类,派生类对象是作为隐含的第一个参数传递。类方法不同于C++或Java静态方法。如果你愿意这些,请参见本文中的staticmethod()部分
@静态方法
静态方法不接收隐式第一个参数。声明静态方法,使用这个成语:C类:@静态方法定义f(arg1,arg2,…):。。。@staticmethod表单是一个函数decorator–请参见函数中的函数定义详细定义。它可以在类上调用(例如C.f())或实例(例如C().f())。实例是除了它的类之外,都被忽略。Python中的静态方法类似类似于Java或C++中的那些。对于更高级的概念,请参见classmethod()。
推荐文章
- 在每个列表元素上调用int()函数?
- 当使用代码存储库时,如何引用资源的相对路径
- 如何在Flask-SQLAlchemy中按id删除记录
- 在Python中插入列表的第一个位置
- Python Pandas只合并某些列
- 如何在一行中连接两个集而不使用“|”
- 从字符串中移除前缀
- 代码结束时发出警报
- 如何在Python中按字母顺序排序字符串中的字母
- 在matplotlib中将y轴标签添加到次要y轴
- 如何消除数独方块的凹凸缺陷?
- 为什么出现这个UnboundLocalError(闭包)?
- 使用Python请求的异步请求
- 如何检查一个对象是否是python中的生成器对象?
- 如何从Python包内读取(静态)文件?