Python中的静态类

33

我曾经在微软的一个页面上看到过这样的说法:当您不需要两个或更多实例时,使用静态类是一种好方法。

我正在编写一个Python程序。如果我对类的每个方法都使用@classmethod,这是否是不好的风格?

5个回答

40

一般来说,这样的用法最好直接在一个模块中使用函数,而不需要用类。


14
如果你没有封装任何数据,那么在Python中完全不需要创建类。 - Daniel Roseman
2
有时我只是从函数开始,但后来意识到,因为我喜欢编写小函数,有时必须在3或4个函数之间传递相同的参数,此时我开始想要封装该参数。我还没有解决这个难题。你有什么想法吗? - Leonid
1
@Leonid 我认为,如果您的函数是独立的但仍然想要在它们之间传递参数,那么只需传递这些参数即可。如果您发现有很多调用具有相同的参数集合,则可以生成一个 namedtuple 或类似的内容来传递。仅为避免传递它们而将东西存储在类中通常不是一个好主意 - 这可能会导致问题。 - Gareth Latty
@Lattyware,我不喜欢将状态作为一种哲学,但真正的函数式语言(如F#,Clojure,Haskell)仍然占据了一个相当小的市场份额。Python是一种多范式语言,所以通常由程序员决定如何使用它。以下陈述比较模糊:“只是为了避免传递参数而将东西存储在类中通常是一个坏主意 - 这可能导致问题。”你能详细说明具体的危险、问题和缺点吗?否则,我可能会认为你对函数持偏见,而对对象持反对态度。 - Leonid
@Leonid 我绝对不主张完全避免状态 - 特别是在 Python 中。我的意思是,如果将值存储在类中,在函数调用的生命周期内就不应该使用它,仅仅是为了避免通过子函数传递该值。危险在于,突然间该状态可能会被外部改变(比如函数在其他地方运行),这可能会导致错误和脆弱性。它还降低了重用这些函数的能力,因为它们依赖于这个状态。 - Gareth Latty

15

这是可怕的风格,除非你确实需要访问这个类。

静态方法[...]不等同于Python中的classmethod。当然,它产生了更多或更少相同的效果,但classmethod的目标实际上是做一些通常甚至不可能的事情(比如继承非默认构造函数)。通常,一个静态方法的惯用翻译是模块级别的函数,而不是classmethod或staticmethod。

来源


14

根据我的经验,创建一个类是解决许多问题的好方法。其中之一是你会经常像使用“普通”类一样使用该类(特别是创建不止一个实例)。另一个原因是坚持使用类作为合理的风格选择;这可以使阅读/维护您的代码的其他人更容易,尤其是如果他们非常熟悉面向对象编程-他们将对类感到舒适。正如其他答复中所指出的那样,仅使用“裸”函数来实现也是合理的。您可以从创建一个类开始,并将其转化为单例/ Borg模式(如果您在谷歌上搜索,��以找到很多示例);这使您可以灵活地(重新)使用该类以满足其他需求。我建议不要采用“静态类”方法,因为这种非常规和非Pythonic的做法会使代码难以阅读和维护。


8
你的回答大部分内容(除第二和最后一句话之外)都是可争议的(我倾向于不同意)且离题。我认为删去所有关于课程有多好的废话会使其更好,你觉得呢? - user395760
3
我对这个答案既同意又不同意,所以我不能决定是按向上还是向下的按钮。不管怎样,我同意对象使代码更易于阅读和维护。我不同意使用单例/博格模式http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Singleton.html。这并不是一个坏的模式;然而,在极其复杂的代码项目中,使用带有类变量的静态方法更易于维护和阅读。是的,这可能在技术上不正确,但初级程序员会感激你。 - Zachary Kraus
这个答案中有很多正确的要点,但它们感觉带着错误的暗示。特别是“如果与其他面向对象的程序员一起工作,则使用类”是一个有效的观点——遵循代码库的风格,始终是一个好建议。我最困扰的是第二句话,它建议使用类,因为你可能会惊讶地发现它经常被重用。我建议进行更多的规划——希望你知道它在你的架构中被重用的频率(但也请注意,制作类的原因不仅仅是重用)。 - acat

6
有几种方法可以实现这个功能。正如其他人所提到的,您可以只使用模块级函数。在这种情况下,模块本身是保存它们的命名空间。如果您需要跟踪状态,则另一个选项是定义一个具有普通方法(使用self)的类,然后定义一个单一的全局实例,并将其实例方法复制到模块命名空间中。标准库“random”模块采用了这种方法--请查看您的Python目录中的lib/python2.5/random.py 。底部有类似于以下内容:
# Create one instance, seeded from current time, and export its methods
# as module-level functions.  [...]
_inst = Random()
seed = _inst.seed
random = _inst.random
uniform = _inst.uniform
...

或者你可以采用你所描述的基本方法(虽然我建议在大多数情况下使用@staticmethod而不是@classmethod)。


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接