用@staticmethod修饰的方法和用@classmethod修饰的方法有什么区别?
当前回答
@staticmethod只是禁用默认函数作为方法描述符。classmethod将函数包装在可调用的容器中,该容器将引用作为第一个参数传递给所属类:
>>> class C(object):
... pass
...
>>> def f():
... pass
...
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>
事实上,classmethod有运行时开销,但可以访问所属的类。或者,我建议使用元类并将类方法放在元类上:
>>> class CMeta(type):
... def foo(cls):
... print cls
...
>>> class C(object):
... __metaclass__ = CMeta
...
>>> C.foo()
<class '__main__.C'>
其他回答
我的贡献展示了@classmethod、@staticmethod和实例方法之间的区别,包括实例如何间接调用@staticmmethod。但是,与其从实例间接调用@staticmethod,不如将其私有化可能更“Python化”。这里没有演示从私有方法获取内容,但基本上是相同的概念。
#!python3
from os import system
system('cls')
# % % % % % % % % % % % % % % % % % % % %
class DemoClass(object):
# instance methods need a class instance and
# can access the instance through 'self'
def instance_method_1(self):
return 'called from inside the instance_method_1()'
def instance_method_2(self):
# an instance outside the class indirectly calls the static_method
return self.static_method() + ' via instance_method_2()'
# class methods don't need a class instance, they can't access the
# instance (self) but they have access to the class itself via 'cls'
@classmethod
def class_method(cls):
return 'called from inside the class_method()'
# static methods don't have access to 'cls' or 'self', they work like
# regular functions but belong to the class' namespace
@staticmethod
def static_method():
return 'called from inside the static_method()'
# % % % % % % % % % % % % % % % % % % % %
# works even if the class hasn't been instantiated
print(DemoClass.class_method() + '\n')
''' called from inside the class_method() '''
# works even if the class hasn't been instantiated
print(DemoClass.static_method() + '\n')
''' called from inside the static_method() '''
# % % % % % % % % % % % % % % % % % % % %
# >>>>> all methods types can be called on a class instance <<<<<
# instantiate the class
democlassObj = DemoClass()
# call instance_method_1()
print(democlassObj.instance_method_1() + '\n')
''' called from inside the instance_method_1() '''
# # indirectly call static_method through instance_method_2(), there's really no use
# for this since a @staticmethod can be called whether the class has been
# instantiated or not
print(democlassObj.instance_method_2() + '\n')
''' called from inside the static_method() via instance_method_2() '''
# call class_method()
print(democlassObj.class_method() + '\n')
''' called from inside the class_method() '''
# call static_method()
print(democlassObj.static_method())
''' called from inside the static_method() '''
"""
# whether the class is instantiated or not, this doesn't work
print(DemoClass.instance_method_1() + '\n')
'''
TypeError: TypeError: unbound method instancemethod() must be called with
DemoClass instance as first argument (got nothing instead)
'''
"""
太长,读不下去了
静态方法本质上是绑定到类(及其实例)的函数
类方法本质上是一种可继承的静态方法。
有关详细信息,请参阅其他人的优秀答案。
我将用一个例子来解释基本的区别。
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-类方法不绑定到对象,而是绑定到类。
关于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类方法的事情,但一旦发布,我发现真正需要的是类方法。但要摆脱静态方法为时已晚。
@staticmethod只是禁用默认函数作为方法描述符。classmethod将函数包装在可调用的容器中,该容器将引用作为第一个参数传递给所属类:
>>> class C(object):
... pass
...
>>> def f():
... pass
...
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>
事实上,classmethod有运行时开销,但可以访问所属的类。或者,我建议使用元类并将类方法放在元类上:
>>> class CMeta(type):
... def foo(cls):
... print cls
...
>>> class C(object):
... __metaclass__ = CMeta
...
>>> C.foo()
<class '__main__.C'>
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用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中获得所有直接子目录