python - 模块函数 vs 静态方法 vs 类方法 vs 无装饰器 : Which idiom is more pythonic?

标签 python static-methods

我是一名 Java 开发人员,经常玩弄 Python。我最近偶然发现了this article其中提到了 Java 程序员在使用 Python 时常犯的错误。第一个引起了我的注意:

A static method in Java does not translate to a Python classmethod. Oh sure, it results in more or less the same effect, but the goal of a classmethod is actually to do something that's usually not even possible in Java (like inheriting a non-default constructor). The idiomatic translation of a Java static method is usually a module-level function, not a classmethod or staticmethod. (And static final fields should translate to module-level constants.)

This isn't much of a performance issue, but a Python programmer who has to work with Java-idiom code like this will be rather irritated by typing Foo.Foo.someMethod when it should just be Foo.someFunction. But do note that calling a classmethod involves an additional memory allocation that calling a staticmethod or function does not.

Oh, and all those Foo.Bar.Baz attribute chains don't come for free, either. In Java, those dotted names are looked up by the compiler, so at runtime it really doesn't matter how many of them you have. In Python, the lookups occur at runtime, so each dot counts. (Remember that in Python, "Flat is better than nested", although it's more related to "Readability counts" and "Simple is better than complex," than to being about performance.)

我觉得这有点奇怪,因为 staticmethod 的文档说:

Static methods in Python are similar to those found in Java or C++. Also see classmethod() for a variant that is useful for creating alternate class constructors.

更令人费解的是这段代码:

class A:
    def foo(x):
        print(x)
A.foo(5)

在 Python 2.7.3 中按预期失败,但在 3.2.3 中工作正常(尽管您不能在 A 的实例上调用该方法,只能在类上调用。)

所以有三种方法可以实现静态方法(如果使用 classmethod 算的话,有四种方法),每一种都有细微的差别,其中一种似乎没有记录。这似乎与 Python 的“应该有一种——最好只有一种——明显的方式来做到这一点”的口头禅不符。 哪个成语是最 Pythonic 的?各有什么优缺点?

这是我目前所理解的:

模块功能:

  • 避免 Foo.Foo.f() 问题
  • 比替代品更污染模块的命名空间
  • 无继承

静态方法:

  • 将与类相关的函数保存在类内部和模块命名空间之外。
  • 允许在类的实例上调用函数。
  • 子类可以覆盖该方法。

类方法:

  • 与静态方法相同,但也将类作为第一个参数传递。

常规方法(仅限 Python 3):

  • 与 staticmethod 相同,但不能在类的实例上调用该方法。

我是不是想多了?这不是问题吗?请帮忙!

最佳答案

考虑它的最直接的方法是考虑该方法需要什么类型的对象才能完成其工作。如果您的方法需要访问实例,请将其设为常规方法。如果它需要访问该类,请将其设为类方法。如果它不需要访问类或实例,请将其设为函数。很少需要将某些东西设为静态方法,但如果你发现你希望一个函数与一个类“分组”(例如,这样它可以被覆盖),即使它不需要访问该类,我猜你可以让它成为一个静态方法。

我要补充一点,将函数放在模块级别不会“污染”命名空间。如果要使用这些函数,它们不会污染命名空间,它们会按照应该使用的方式使用它。函数是模块中的合法对象,就像类或其他任何东西一样。如果没有任何理由存在,就没有理由在类中隐藏函数。

关于python - 模块函数 vs 静态方法 vs 类方法 vs 无装饰器 : Which idiom is more pythonic?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11788195/

相关文章:

python - 找不到元素 'xml' 的声明

python - 为什么一些 numpy 数据类型是 JSON 可序列化的,而另一些则不是?

java - 通过实例调用静态函数时是否会忽略运行时实例?

.net - 接口(interface)/抽象类中的静态方法

python - openerp中如何将数据存储到动态字段?

python - 如何在字典中查找匹配项

Python 脚本无法访问 Docker 镜像中的 .jar 文件

php - 在同一个类中调用 __call 而不是 __callstatic,而不是调用另一个类

php - 获取父类中子类的名称(静态上下文)

C++ 编译时多态性