42

我来自 Java 背景,我是 python 新手。我有几个脚本,它们共享一些与读写文件相关的应用程序独有的帮助函数。一些与阅读相关的功能,一些与写作相关的功能。在寻找正确的方法时,我看到了:Python 中的静态方法?

他在回答中提到:

最后,谨慎使用静态方法!在 Python 中很少有需要静态方法的情况,而且我已经看到它们多次使用,其中单独的“顶级”函数会更清晰。

我不太了解顶级函数,我不确定这个简单的例子哪个更好:1)为具有静态读取器函数的读取器创建一个类,并且为编写器创建一个类,或者 2)声明这些助手作为全局函数,为什么?

编辑:关于这个主题的非常好的文章我刚刚发现http://tomayko.com/writings/the-static-method-thing

4

5 回答 5

52

在 Java 中,到处都使用类是一种(恕我直言错误)的想法,甚至只是将不共享任何状态的静态函数组合在一起(因此这些类永远不会被实例化)。

这里的 Python 有所不同;如果您的函数没有某些共享状态1(因此在 Java 中通常是static函数)并且与“真实”类(=实际实例化的类)没有紧密相关,您只需在 a 中使用自由函数模块。

这背后的原因是,只有当你真正想要实例化它时才需要一个类,因此将一个类作为几个不需要共享特定于实例状态的函数的容器是没有用的。

实际上,您可以在某种程度上将模块视为一个static类——即函数(=静态方法)、模块变量(=静态字段)和类型的容器。

Python 中的好处是拥有顶级函数不会产生全局命名空间污染问题,因为在 Python 中,顶级函数/对象/... 仍然是模块范围的。因此,您仍然可以按模块对功能进行分组,而无需使用不必要的class-tax。


  1. 实际上,它们可以有一些共享状态,以模块级变量的形式(所以,单例);再次,类比模块静态类似乎成立。
于 2013-08-15T22:04:00.560 回答
14

来自 Python 之禅 ( import this) :

Namespaces are one honking great idea -- let's do more of those!

使用 Java 等语言创建静态方法的主要原因之一是确保这些方法不会最终污染全局命名空间。(尽管 Java 通过完全禁止“包级”函数来强制执行自己的命名空间约定!)在 Python 中,所有“顶级”函数都自动放置在包含这些函数的模块的命名空间中,因此没有污染全局的危险命名空间这种方式。

换句话说,像许多其他语言一样,Python 可以通过几种不同的方式创建命名空间。在这种情况下,几乎不需要创建一个只包含静态方法的类,因为模块服务于相同的命名空间目的而没有与定义类相关的混乱(或认知负荷)。

于 2013-08-15T22:11:20.093 回答
6

这是一个命名空间污染的问题。如果您有一个具有多个类的模块和一些仅对某个类及其后代有意义的函数,则将其设为静态方法。可以使用类名或使用类的对象来调用静态方法。

>>> class A(object):
...     @staticmethod
...     def static_1():
...             print 'i am static'
...     def a(self):
...             self.static_1()
...
>>> A.static_1()
i am static
>>> a=A()
>>> a.a()
i am static
>>> a.static_1()
i am static
>>> class B(A):
...     pass
...
>>> b=B()
>>> b.static_1()
i am static
>>>
于 2013-08-15T22:20:38.167 回答
5

如果函数与类相关,则将其设为静态方法。例如:

class DBobject():
    name = StringProperty()

    @staticmethod
    def get_by_name(name):
        return db.select('select * from DBobject where name = "%s"' % name)

python = DBobject.get_by_name('python')

也就是说,该方法与 DBobject 类完全相关,因此它应该是一个静态方法。

于 2013-08-15T22:08:49.767 回答
1

Python 静态方法的另一个方面是,当在实例上调用时,它们在调用它们的变量的类型上是多态的,尽管没有self.

例如:

class BaseClass:
    @staticmethod
    def my_method():
        return 0


class SubclassLeft:
    @staticmethod
    def my_method():
        return "left"


class SubclassRight:
    @staticmethod
    def my_method():
        return "right"


instances = [BaseClass(), SubclassLeft(), SubclassRight()]

for i in instances:
    print(i.my_method())

运行此结果

$ python example.py
0
left
right
于 2018-07-09T18:14:21.557 回答