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

时间:2016-01-07 20:24:29

标签: python class methods binding descriptor

我有一个像类一样的字典,其方法可以返回其键,值和项的视图。这样做的方法尽可能简单:

class MyType(collections.MutableMapping):

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

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

class MyType(collections.MutableMapping):

    keys = collections.KeysView

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

class MyType(collections.MutableMapping):

    keys = bind_constructor_as_method(collections.KeysView)

我觉得functools中应该有一些可以完成这项任务的东西,但是没有任何东西可以作为正确的答案乍一看。也许是functools.partial,但这个名字并不能说明我想要做的事情。

我是否只需要手动滚动一个自定义描述符类来制作这样的工作?

注意

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

2 个答案:

答案 0 :(得分:1)

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及更高版本。

答案 1 :(得分:0)

经过一番思考(以及来自这篇SO 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兼容性,您应该 使用{{1}的第三个可选class参数}};它存在于Python 2中,但在Python 3中显然已被删除。