我习惯于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看起来像一个可迭代的,但它没有帮助。我错过了什么?
答案 0 :(得分:18)
__contains__
之类的特殊方法只有在类上定义时才是特殊的,而不是在实例上定义的(Python 2中的遗留类除外,你不应该 使用它)。< / p>
那么,你的代表团是否在班级:
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__
重新分配给一个新的类对象(其行为与前一个类似,但有一个空的dict,除了这个self
之外没有其他实例),您将分配给self.__magicname__
的旧式课程中的任何位置,而是分配给self.__class__.__magicname__
(并确保它是内置的或staticmethod
,而不是普通的Python函数,除非当然在某些不同情况下,您确实希望它在实例上调用时接收self
。
顺便提一下,此in
类实例上的BlackMagic
运算符更快,与之前提出的任何解决方案相比,或者至少所以我用我平时可靠的-mtimeit
进行测量(直接进入built-in method
,而不是遵循涉及继承和描述符的正常查找路由,削减一些开销。)
自动执行self.__class__
- 每个实例的元类的元类并不难编写(它可以在生成的类的__new__
方法中执行脏工作,也可能将所有魔术名称设置为实际上,如果在实例上分配,则通过__setattr__
或许多许多属性进行分配。但只有在对这个功能的需求真正普及的情况下才能证明这一点(例如,将一个庞大的古老Python 1.5.2项目移植到现代Python中,包括Python 3)。
我推荐“聪明”或“黑魔法”解决方案吗?不,我不这样做:几乎总是以简单,直接的方式做事情。但是“几乎”在这里是一个重要的词,并且很高兴能够获得这种先进的“钩子”,用于罕见但并非不存在的情况,在这种情况下,它们的使用实际上可能是有保证的。