从 class 构造函数创建绑定方法

Create bound method from class constructor

我有一本像 class 这样的字典,其中的方法可以 return 查看其键、值和项目。这样做的方法非常简单:

class MyType(collections.MutableMapping):

    def keys(self):
        return collections.KeysView(self)

但是,为如此简单的事情创建一个方法似乎毫无意义;我所做的只是将 self 传递给另一个可调用对象。我宁愿简单地将 KeysView 的 class 构造函数视为绑定方法。执行以下操作会创建一个嵌套的 class(这很好,因为有时这正是您想要的),但它看起来更接近我想要做的:

class MyType(collections.MutableMapping):

    keys = collections.KeysView

Python 或其标准库是否有内置功能来执行此操作?也许是这样的:

class MyType(collections.MutableMapping):

    keys = bind_constructor_as_method(collections.KeysView)

我觉得 functools 中应该有一些东西可以完成这项工作,但没有任何东西乍一看是正确答案。也许 functools.partial,但名称并不能很好地描述我正在尝试做的事情。

我是否只需要手动滚动一个自定义描述符 class 就可以完成这样的工作?

注意:

为了工作,我经常需要使用 Python 2.7,因此尽管 Python 3.x 答案仍然受到赞赏(并且有用),但它们可能不会完全缓解问题我个人。但是,他们可能会帮助其他人解决这个问题,所以请仍然包括他们!

functools.partialmethod() 就是您要找的。这将创建一个方法,其中 self 是第一个参数。

import functools

class MyType(collections.MutableMapping):

    keys = functools.partialmethod(collections.KeysView)

你还可以指定其他参数,比如如果你想将 self, 1, 2, key=5 传递给 func(),你可以做 functools.partialmethod(func, 1, 2, key=5).

但请注意,这仅适用于 Python 3.4 及更高版本。

经过一番思考(以及来自 SO post here 的一些帮助),我想出了另一个适用于 Python 版本 2 和 3 的解决方案,尽管它是不那么地道。正如@Artyer 建议的那样使用 partialmethod 时发生的事情绝对不是很清楚。真的,这就是 Python 在创建新实例时在幕后所做的事情,但更加明确;你看到香肠是如何制作的。 :/

import types
import collections

class MyType(collections.MutableMapping):
    def __init__(self, *args, **kwargs):
        # do class specific stuff here

        # create bound method per instance
        self.keys = types.MethodType(collections.KeysView, self)

更好的是,我们可以在 __new__ 中做到这一点,以更加确定继承 类 得到它:

import types
import collections

class MyType(collections.MutableMapping):
    def __new__(cls, *args, **kwargs):
        self = super(MyType, cls).__new__(cls)

        # create bound method per instance
        self.keys = types.MethodType(collections.KeysView, self)
        return self

如果您不喜欢 types.MethodType 的相对无证性质,您可以使用 functools.partial 代替:

import functools
import collections

class MyType(collections.MutableMapping):
    def __new__(cls, *args, **kwargs):
        self = super(MyType).__new__(cls)

        # create bound method per instance
        self.keys = functools.partial(collections.KeysView, self)
        return self

注意: 对于 Python 2/3 兼容性,您应该 而不是 types.MethodType 使用第三个可选的 class 参数;它存在于 Python 2 中,但显然在 Python 3 中被删除。