使用 @staticmethod 有什么好处吗?
我在想你们的代码里有没有用到 @staticmethod 这个装饰器。
就我个人来说,我不太用这个,因为写 @staticmethod 比写 self 要多打几个字。
用它的唯一好处(对我来说)可能就是让代码更清晰,但因为我通常会为方法写描述给 sphinx,所以我总是会说明这个方法是否使用了对象。
或者我是不是应该开始用 @staticmethod 这个装饰器呢?
4 个回答
@staticmethod
这个装饰器可以让你少打字,而且让代码看起来更清晰。
class Example:
@staticmethod
def some_method():
return
这和下面的写法是一样的:
class Example:
def some_method():
return
some_method = staticmethod(some_method)
我觉得你可能对Python中的静态方法有些困惑,因为这个术语和其他语言不太一样。普通方法是“绑定”到实例上的(用 self
表示),类方法是“绑定”到类上的(用 cls
表示),而静态方法根本不“绑定”到任何东西(它不能访问实例或类的属性)。
你可以查看这些链接了解更多:
假设我们想在一个叫做 Math
的类里定义一个 abs
方法,那么我们有两种选择:
class Math():
def abs(n):
if n>0:
return n
else:
return -n
class Math2():
@staticmethod
def abs(n):
if n>0:
return n
else:
return -n
在 Python2 中:
>>> Math.abs(-2)
TypeError: unbound method abs() must be called with Math instance as
first argument (got int instance instead)
>>>Math().abs(-2)
TypeError: abs() takes exactly 1 argument (2 given)
>>> Math2.abs(-2)
2
>>> Math2().abs(-2)
2
在 Python2 里,调用 Math().abs(-2)
时,系统会自动把它当作 Math().abs(self, -2)
来处理,所以你需要使用 @staticmethod
来标记这个方法。
在 Python3 中:
>>>Math.abs(-3)
3
>>>Math().abs(-3)
TypeError: abs() takes 1 positional argument but 2 were given
>>>Math2.abs(-3)
3
>>>Math2().abs(-3)
3
在 Python3 里,你可以直接用 classname.method()
来调用方法,而不需要静态方法的标记,但如果有人尝试用 instance.method()
来调用,就会出现类型错误(TypeError)。
是否使用 @staticmethod
取决于你想要实现什么。如果只是因为觉得多打一个装饰器麻烦而不去用,那就有点傻了(没有冒犯的意思!),这说明你可能还没有理解 Python 中 静态方法 的概念!
静态方法和类以及类的实例是独立的。它们只是把类当作一个命名空间来使用。如果你不加 @staticmethod
装饰器,你就创建了一个实例方法,这个方法必须先创建一个实例才能使用。
这里有一个非常简单的类 Foo
:
>>> class Foo(object):
... @staticmethod
... def foo():
... print 'foo'
...
... def bar(self):
... print 'bar'
现在,Foo.foo()
是一个静态方法,可以直接调用:
>>> Foo.foo()
foo
而 Foo.bar()
则是一个 实例方法,只能通过 Foo
的实例(对象)来调用:
>>> Foo.bar()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with Foo instance as first argument (got nothing instead)
>>> foo = Foo()
>>> foo.bar()
bar
回答你的问题:如果你想定义一个静态方法,就用 @staticmethod
。否则,就不需要。
如果你有一个方法不使用 self
,因此 可以 写成静态方法,那就问问自己:你是否希望在没有实例的情况下从外部访问这个函数?大多数情况下,答案是:不。