我习惯于Python允许一些巧妙的技巧将功能委托给其他对象。一个例子是委托给包含的对象。

但它接缝,我没有运气,当我想委托__contains __:

class A(object):
    def __init__(self):
       self.mydict = {}
       self.__contains__ = self.mydict.__contains__

a = A()
1 in a

我明白了:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: argument of type 'A' is not iterable

我错了什么?当我打电话给.__包含__(1)时,一切顺利。我甚至试图在A中定义一个__iter __方法,使A看起来像一个可迭代的,但它没有帮助。我错过了什么?

有帮助吗?

解决方案

__ contains __ 等特殊方法只有在类上定义时才是特殊的,而不是在实例上定义(Python 2中的遗留类除外,你应该使用它们)。

那么,你的代表团是否在班级:

class A(object):
    def __init__(self):
       self.mydict = {}

    def __contains__(self, other):
       return self.mydict.__contains__(other)

我实际上更喜欢将后者拼写为在self.mydict 中返回其他内容,但这是一个次要的样式问题。

修改:if和when“完全动态的每个实例重定向特殊方法” (就像提供的旧式类一样)是必不可少的,用新式类实现它并不困难:你只需要每个具有这种特殊需要的实例都包含在它自己的特殊类中。例如:

class BlackMagic(object):
    def __init__(self):
        self.mydict = {}
        self.__class__ = type(self.__class__.__name__, (self.__class__,), {})
        self.__class__.__contains__ = self.mydict.__contains__

基本上,在一点点黑魔法将 self .__ class __ 重新分配给一个新的类对象(其行为与前一个类似,但是有一个空的dict,除了这个 self ),您将分配给 self .__ magicname __ 的旧式类中的任何位置,分配给 self .__ class __.__ magicname __ (并确保它是一个内置的或 staticmethod ,而不是一个普通的Python函数,除非在某些不同的情况下你确实希望它在实例上调用时接收 self 。 / p>

顺便提一下,此 BlackMagic 类的实例上的 运算符更快,因为它发生了,而不是之前提出的任何一个解决方案 - 或者至少我用我通常可靠的 -mtimeit 进行测量(直接转到内置方法,而不是遵循涉及继承的正常查找路由和描述符,削减了一些开销。)

自动化 self .__ class __ -per-instance idea的元类并不难写(它可以在生成的类的 __ new __ 方法中执行脏工作,并且如果在实例上分配,也可以通过 __ setattr __ 或许多许多属性)将所有魔术名称设置为在类上实际分配。但只有在对这个功能的需求真正普及的情况下才能证明这一点(例如,将一个庞大的古代Python 1.5.2项目移植到现代Python,包括Python 3),这个项目大量使用“每个实例特殊方法”。

推荐“聪明”吗?或“黑魔法”解决方案?不,我不这样做:几乎总是以简单,直接的方式做事情。但是“几乎”这里是一个重要的词,手头有这样的高级“钩子”,这很好。对于罕见但并非不存在的情况,实际上可能需要使用它们。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top