Dov*_*val 65 python static-methods
我是一名Java开发人员,他开玩笑地玩弄Python.我最近偶然发现了这篇文章,其中提到了Java程序员在学习Python时常犯的错误.第一个引起了我的注意:
Java中的静态方法不能转换为Python类方法.哦,当然,它会产生或多或少相同的效果,但类方法的目标实际上是做一些在Java中通常甚至不可能的事情(比如继承非默认的构造函数).Java静态方法的惯用翻译通常是模块级函数,而不是类方法或静态方法.(静态最终字段应转换为模块级常量.)
这不是一个性能问题,但是一个必须使用Java-idiom代码的Python程序员会因为输入Foo.Foo.someMethod而感到非常烦恼,因为它应该只是Foo.someFunction.但请注意,调用classmethod涉及额外的内存分配,调用static方法或函数不会.
哦,所有那些Foo.Bar.Baz属性链也不是免费的.在Java中,编译器会查找那些带点名称的名称,因此在运行时,它们中有多少名称并不重要.在Python中,查找在运行时发生,因此每个点都很重要.(请记住,在Python中,"Flat优于嵌套",虽然它与"可读性计数"和"简单优于复杂"相关,而不是与性能有关.)
我发现这有点奇怪,因为staticmethod的文档说:
Python中的静态方法与Java或C++中的静态方法类似.另请参阅classmethod()以获取对创建备用类构造函数有用的变体.
更令人费解的是这段代码:
class A:
def foo(x):
print(x)
A.foo(5)
Run Code Online (Sandbox Code Playgroud)
在Python 2.7.3中按预期失败,但在3.2.3中工作正常(尽管你不能在A的实例上调用该方法,只能在类上调用.)
因此,有三种方法可以实现静态方法(如果使用classmethod计算,则有四种方法),每种方法都有细微差别,其中一种看似无法记录.这似乎与Python的口头禅是不一致的应该有一个 - 最好只有一个 - 明显的方式来做到这一点.哪个成语是最Pythonic?各自的优点和缺点是什么?
这是我到目前为止所理解的:
模块功能:
静态方法:
类方法:
常规方法(仅限Python 3):
我是否想过这个?这不是问题吗?请帮忙!
Bre*_*arn 83
考虑它的最直接的方法是考虑方法需要什么类型的对象才能完成它的工作.如果您的方法需要访问实例,请将其设为常规方法.如果需要访问该类,请将其作为类方法.如果它不需要访问类或实例,请将其设置为函数.很少需要使用静态方法,但如果你发现你想要一个函数与一个类"分组"(例如,所以它可以被覆盖),即使它不需要访问类,我猜你可以把它变成一个静态的方法.
我想补充说,在模块级别放置函数不会"污染"命名空间.如果要使用这些函数,它们不会污染命名空间,它们就像应该使用它一样使用它.函数是模块中的合法对象,就像类或其他任何东西一样.如果没有任何理由在某个类中隐藏函数,则没有理由隐藏它.
smc*_*mci 28
BrenBarn给出了很好的答案,但我会改变'如果它不需要访问类或实例,那就让它成为一个函数':
"如果它不需要访问类或实例...但是主题相关的类(典型的例子:通过其它类的方法中使用或由交替的构造方法的辅助函数和转换函数),然后使用静态方法
否则使它成为模块功能
glg*_*lgl 15
这不是一个真正的答案,而是一个冗长的评论:
更令人费解的是这段代码:
Run Code Online (Sandbox Code Playgroud)class A: def foo(x): print(x) A.foo(5)在Python 2.7.3中按预期失败,但在3.2.3中工作正常(尽管你不能在A的实例上调用该方法,只能在类上调用.)
我会试着解释一下这里发生了什么.
严格来说,这是滥用"正常"实例方法协议.
你在这里定义的是一个方法,但是第一个(也是唯一的)参数没有命名self,但是x.当然你可以在一个实例中调用该方法A,但是你必须像这样调用它:
A().foo()
Run Code Online (Sandbox Code Playgroud)
要么
a = A()
a.foo()
Run Code Online (Sandbox Code Playgroud)
所以实例作为第一个参数赋予函数.
通过课程调用常规方法的可能性一直存在并且可以工作
a = A()
A.foo(a)
Run Code Online (Sandbox Code Playgroud)
在这里,当您调用类的方法而不是实例时,它不会获得自动获取的第一个参数,但您必须提供它.
只要这是一个实例A,一切都很好.给它别的东西是IMO滥用协议,因此Py2和Py3之间的区别:
在Py2中,A.foo变换为未绑定的方法,因此要求其第一个参数是它"生活"的类的实例.用其他东西调用它将失败.
在Py3中,此检查已被删除,A.foo并且只是原始的功能对象.所以你可以用一切作为第一个参数调用它,但我不会这样做.方法的第一个参数应始终命名self并具有语义self.