模块函数 vs 静态方法 vs 类方法 vs 没有装饰器:哪个习语更 Pythonic? [英] Module function vs staticmethod vs classmethod vs no decorators: Which idiom is more pythonic?

查看:59
本文介绍了模块函数 vs 静态方法 vs 类方法 vs 没有装饰器:哪个习语更 Pythonic?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一名 Java 开发人员,经常玩弄 Python.我最近偶然发现了这篇文章,其中提到了 Java 程序员常犯的错误当他们拿起 Python 时.第一个引起了我的注意:

I'm a Java developer who's toyed around with Python on and off. I recently stumbled upon this article which mentions common mistakes Java programmers make when they pick up Python. The first one caught my eye:

Java 中的静态方法不会转换为 Python 类方法.哦当然,它或多或少会产生相同的效果,但 classmethod 的目标实际上是做一些在 Java 中通常甚至不可能的事情(比如继承非默认构造函数).Java 静态方法的惯用翻译通常是模块级函数,而不是类方法或静态方法.(并且静态 final 字段应该转换为模块级常量.)

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

这不是一个很大的性能问题,但是一个 Python 程序员必须使用像这样的 Java 习惯用法代码,当它应该只是 Foo.someFunction 时输入 Foo.Foo.someMethod 会相当恼火.但请注意,调用类方法涉及额外的内存分配,而调用静态方法或函数则不会.

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.

哦,所有那些 Foo.Bar.Baz 属性链也不是免费的.在 Java 中,编译器会查找这些带点的名称,因此在运行时,您拥有多少个名称实际上并不重要.在 Python 中,查找发生在运行时,因此每个点都很重要.(请记住,在 Python 中,扁平优于嵌套",尽管它与可读性计数"和简单优于复杂"更相关,而不是与性能有关.)

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 的文档说:

I found this a bit strange because the documentation for staticmethod says:

Python 中的静态方法类似于 Java 或 C++ 中的静态方法.另请参阅 classmethod() 以了解可用于创建替代类构造函数的变体.

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.

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

Even more puzzling is that this code:

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

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

Fails as expected in Python 2.7.3 but works fine in 3.2.3 (although you can't call the method on an instance of A, only on the class.)

因此有三种实现静态方法的方法(如果使用 classmethod 计算则为四种),每种方法都有细微的差别,其中一种似乎没有记录.这似乎与 Python 的口头禅应该有一种——最好只有一种——明显的方法来做到这一点.哪个习语是最 Pythonic 的?各自的优缺点是什么?

So there's three ways to implement static methods (four if you count using classmethod), each with subtle differences, one of them seemingly undocumented. This seems at odds with Python's mantra of There should be one-- and preferably only one --obvious way to do it. Which idiom is the most Pythonic? What are the pros and cons of each?

以下是我目前的理解:

模块功能:

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

静态方法:

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

类方法:

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

常规方法(仅限 Python 3):

  • 与静态方法相同,但不能在类的实例上调用该方法.

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

Am I overthinking this? Is this a non-issue? Please help!

推荐答案

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

The most straightforward way to think about it is to think in terms of what type of object the method needs in order to do its work. If your method needs access to an instance, make it a regular method. If it needs access to the class, make it a classmethod. If it doesn't need access to the class or the instance, make it a function. There is rarely a need to make something a staticmethod, but if you find you want a function to be "grouped" with a class (e.g., so it can be overridden) even though it doesn't need access to the class, I guess you could make it a staticmethod.

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

I would add that putting functions at the module level doesn't "pollute" the namespace. If the functions are meant to be used, they're not polluting the namespace, they're using it just as it should be used. Functions are legitimate objects in a module, just like classes or anything else. There's no reason to hide a function in a class if it doesn't have any reason to be there.

这篇关于模块函数 vs 静态方法 vs 类方法 vs 没有装饰器:哪个习语更 Pythonic?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆