【问题标题】:Create bound method from class constructor从类构造函数创建绑定方法
【发布时间】:2016-01-07 20:24:28
【问题描述】:

我有一个类似字典的类,其方法返回其键、值和项的视图。执行此操作的方法非常简单:

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 的答案仍然受到赞赏(并且有用),但它们可能不会完全缓解我个人的问题。但是,他们可能会帮助其他人解决这个问题,所以仍然请包括他们!

【问题讨论】:

    标签: python class methods binding descriptor


    【解决方案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 及更高版本。

    【讨论】:

    • 我应该更好地标记我的问题。我的大部分代码需要在 Python 2.7 中运行以用于工作环境,partialmethod 仅在 3.4 中可用。即使在个人的东西上,我也希望它尽可能向后兼容,特别是如果它是开源的(许多人仍然受限于 Python 的 2.x 行)。但是,这个答案仍然有用。我将查看标准库,看看他们为此做了什么,我可以看看是否值得向后移植或修改以满足我自己的需要。
    • @eestrada 好吧,你总是可以尝试导入它,当你失败时,在任何 Python 3.4+ 解释器中实现你自己版本的 functools.partialmethod(你可以通过运行import inspect; import functools; print(inspect.getsource(functools.partialmethod)) 找到它) .
    • 是的,使用try/except 导入是个好主意;我过去经常为版本之间不同的其他事情(如functools.lru_cacheunicode)这样做。 partialmethod 的源代码不是很长,但它足够长,可能需要保存在单独的模块中。我希望我可以在几行中伪造一些东西,我可以在需要时将它们作为样板包含在内,但似乎制作一个完整的描述符类对于正确的行为是必要的。
    【解决方案2】:

    经过一番思考(以及来自此 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,您应该不要types.MethodType 使用第三个可选的class 参数;它存在于 Python 2 中,但显然已在 Python 3 中删除。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-17
      • 2018-06-16
      • 1970-01-01
      • 1970-01-01
      • 2016-05-31
      • 1970-01-01
      • 2022-01-25
      • 1970-01-01
      相关资源
      最近更新 更多