我已经习惯了 Python 允许一些巧妙的技巧将功能委托(delegate)给其他对象。一个例子是委托(delegate)给包含的对象。
但它接缝,我没有运气,当我想委托(delegate) __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
我做错了什么?当我调用 a.__contains __(1) 时,一切都很顺利。我什至试图在 A 中定义一个 __iter __ 方法来使 A 看起来更像一个可迭代对象,但它没有帮助。我在这里错过了什么?
最佳答案
__contains__
等特殊方法只有在类上定义时才是特殊的,而不是在实例上(Python 2 中的遗留类除外,您无论如何都不应使用它们) ).
那么,在类(class)层面做你的代表团:
class A(object):
def __init__(self):
self.mydict = {}
def __contains__(self, other):
return self.mydict.__contains__(other)
我实际上更愿意将后者拼写为 return other in self.mydict
,但这是一个小的样式问题。
编辑:如果“特殊方法的完全动态的按实例重定向”(如提供的旧式类)是必不可少的,那么用新式类实现它并不难:你只需要将具有这种特殊需求的每个实例都包装在自己的特殊类中。例如:
class BlackMagic(object):
def __init__(self):
self.mydict = {}
self.__class__ = type(self.__class__.__name__, (self.__class__,), {})
self.__class__.__contains__ = self.mydict.__contains__
本质上,在将 self.__class__
重新分配给一个新的类对象(其行为与前一个类对象一样,但有一个空的字典,除了这个之外没有其他实例 >self
),在旧式类中的任何地方,你将分配给 self.__magicname__
,改为分配给 self.__class__.__magicname__
(并确保它是一个内置的或 staticmethod
,而不是一个普通的 Python 函数,当然除非在某些不同的情况下你确实希望它在调用实例时接收 self
。/p>
顺便说一下,这个 BlackMagic
类的实例上的 in
操作符 faster 碰巧比之前提出的任何一个解决方案——或者至少我正在用我通常信任的-mtimeit
进行测量(直接转到内置方法
,而不是遵循涉及继承和描述符,减少了一些开销)。
一个元类来自动化 self.__class__
-per-instance 的想法并不难写(它可以在生成的类的 __new__
方法中完成肮脏的工作,如果通过 __setattr__
或许多 many 属性分配给实例,也可能将所有魔法名称设置为实际分配给类)。但只有当对该功能的需求真的很普遍时(例如,将一个巨大的古老 Python 1.5.2 项目自由地使用“每个实例的特殊方法”移植到现代 Python,包括 Python 3),这才是合理的。
我推荐“聪明”或“黑魔法”解决方案吗?不,我不知道:几乎总是以简单、直接的方式做事更好。但是“几乎”在这里是一个重要的词,很高兴手头有这样的高级“钩子(Hook)”,用于实际可能需要使用它们的罕见但并非不存在的情况。
关于python - 在 Python : delegating __contains__ to contained-object correctly 中模拟成员资格测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1022499/