python - 我应该使用静态方法还是顶级函数

时间:2013-08-15 21:59:18

标签: python design-patterns static

我来自Java背景,我是python的新手。我有几个脚本共享一些与读取和写入文件相关的应用程序独有的辅助函数。一些与阅读相关的功能,一些与写作相关。在寻找正确的方法时,我看到了这一点:Static methods in Python?

他在回答中提到:

  

最后,谨慎使用static方法!在Python中很少需要使用静态方法,并且我已经看到它们多次使用,其中单独的"顶级"功能会更清楚。

我不太了解顶级功能,而且我不确定这个简单的例子哪个更好:1)为具有静态读取器功能的读者创建一个类,对于一个作者也是如此或者2)将这些帮助者声明为全局函数,为什么?

编辑:真的关于此主题的好文章我刚刚找到http://tomayko.com/writings/the-static-method-thing

5 个答案:

答案 0 :(得分:42)

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

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

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

实际上,您可以稍微将模块视为static类 - 即函数(=静态方法),模块变量(=静态字段)和类型的容器。 / p>

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


  1. 实际上,他们可以以模块级变量的形式存在一些共享状态(所以,单身人士);再次,类比模块 - 静态类似乎成立。

答案 1 :(得分:12)

来自Python的禅宗(import this):

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

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

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

答案 2 :(得分:4)

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

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类完全相关,因此它应该是一个静态方法。

答案 3 :(得分:4)

这是命名空间污染的问题。如果你有一个包含多个类的模块和一些只对某个类及其后代有意义的函数,那么将它作为一个静态方法。可以使用类名或使用类的对象来调用静态方法。

>>> 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
>>>

答案 4 :(得分:0)

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