从类外部的现有方法创建静态方法? (“未绑定方法”错误)

Posted

技术标签:

【中文标题】从类外部的现有方法创建静态方法? (“未绑定方法”错误)【英文标题】:Create staticmethod from an existing method outside of the class? ("unbound method" error) 【发布时间】:2012-02-13 17:55:24 【问题描述】:

如何在定义类之后使类方法静态?换句话说,为什么第三种情况会失败?

>>> B类: ... @静态方法 ...定义富(): ... 经过 ... >>> b.foo() >>> C类: ...定义富(): ... 经过 ... foo = 静态方法( foo ) ... >>> c.foo() >>> D类: ...定义富(): ... 经过 ... >>> d.foo = 静态方法(d.foo) >>> d.foo() 回溯(最近一次通话最后): 中的文件“”,第 1 行 类型错误:必须以 d 实例作为第一个参数调用未绑定的方法 foo()(什么都没有)

【问题讨论】:

【参考方案1】:

类定义后,foo 是一个未绑定的方法对象(将函数与类绑定的包装器),而不是函数。包装器将尝试将类的实例 (self) 作为第一个参数传递给函数,因此它抱怨您没有给它一个。

staticmethod() 应该只与函数一起使用。虽然类仍在定义中(如在您的bc 中)foo() 仍然是一个函数,因为当类定义完成时应用方法包装器。

可以从未绑定的方法对象中提取函数,应用staticmethod(),然后将其分配回类。

class d(object):
    def foo():
       pass

d.foo = staticmethod(d.foo.im_func)

在 Python 3 中,没有未绑定的实例方法(存储在类中的方法是普通函数)。因此,您的原始代码实际上可以在 Python 3 上正常运行。

一种适用于 Python 2 和 Python 3 的方法是:

d.foo = staticmethod(d.__dict__['foo'])

(它还避免了创建和丢弃方法包装器。)

【讨论】:

不应该是d.foo.im_func吗? 嗯,你需要用staticmethod 标记它们,以便在实例上等效地调用它们,而不仅仅是类本身。 d.foo() 可以使用或不使用 staticmethod 包装,但 d().foo() 会爆炸(它会尝试通过 selffoo 不接受)。当然,没有与实例相关的特性需要在实例上调用它们,但对于 DRY,引用静态方法的方法可以并且应该将其调用为 self.foo() 而不是显式命名类。 另外,使用 im_func 意味着在 Py2 上创建然后丢弃未绑定的方法,如果代码必须在 Py2 和 Py3 上运行(后者甚至没有 im_func 属性),则它是不可移植的在绑定方法上,更不用说原始函数了)。您可以通过直接访问类字典来完全绕过未绑定方法的创建,从而绕过描述符协议,使其效率更高,并且完全可移植:d.foo = staticmethod(d.__dict__['foo']) @ShadowRanger 感谢 cmets。我已经编辑了我的答案。我想我的很多近五年前的答案也可以得到改进......【参考方案2】:

你必须传递函数,而不是未绑定的方法。

>>> class d:
...   def foo():
...     pass
... 
>>> d.foo = staticmethod(d.foo.im_func)
>>> d.foo()

【讨论】:

以上是关于从类外部的现有方法创建静态方法? (“未绑定方法”错误)的主要内容,如果未能解决你的问题,请参考以下文章

从类中分解所有依赖项的最简单、最快的方法

从类加载进内存到对象创建,各部分的执行顺序

python如何从类体内调用静态方法[重复]

如何从类变量中引用静态方法[重复]

在 Python(tkinter)中从类的外部更改类的私有属性(标签)

未绑定方法 createDataFrame()