在Python中模拟成员资格测试:将_包含_正确地委托给包含的对象
我习惯于Python允许一些巧妙的技巧将功能委托给其他对象。一个例子是对包含对象的委托 但是,我没有运气,当我想授权时,包含:在Python中模拟成员资格测试:将_包含_正确地委托给包含的对象,python,containers,delegation,emulation,iterable,Python,Containers,Delegation,Emulation,Iterable,我习惯于Python允许一些巧妙的技巧将功能委托给其他对象。一个例子是对包含对象的委托 但是,我没有运气,当我想授权时,包含: class A(object): def __init__(self): self.mydict = {} self.__contains__ = self.mydict.__contains__ a = A() 1 in a 我得到: Traceback (most recent call last): File "<st
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行,在
TypeError:类型为“A”的参数不可编辑
我做错了什么?当我调用._包含_(1)时,一切都很顺利。我甚至试图在A中定义一个iter方法,使A看起来更像一个iterable,但没有帮助。我在这里遗漏了什么?特殊方法,如
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu>仅当在类上定义时才是特殊的,而不是在实例上(除了在
那么,你的代表团是否在班级层面:
class A(object):
def __init__(self):
self.mydict = {}
def __contains__(self, other):
return self.mydict.__contains__(other)
实际上,我更喜欢将后者拼写为self.mydict中的return other,但这是一个小的样式问题
编辑:如果“特殊方法的完全动态每个实例重定向”(如提供的老式类)是必不可少的,那么用新型类实现它并不困难:您只需要将每个具有特殊需要的实例包装在其自己的特殊类中。例如:
class BlackMagic(object):
def __init__(self):
self.mydict = {}
self.__class__ = type(self.__class__.__name__, (self.__class__,), {})
self.__class__.__contains__ = self.mydict.__contains__
本质上,经过一点点的黑魔法将self.\uuu class\uuuu
重新分配给一个新的类对象(它的行为与前一个对象一样,但有一个空的dict,除了这个self
)之外没有其他实例),在一个旧样式类中的任何地方都可以分配给self.\uu magicname\uu
,改为分配给self.\uuuuu class.\uuuuu magicname.\uuuuu
(并确保它是内置的或staticmethod
,而不是普通的Python函数,当然,除非在某些不同的情况下,您确实希望它在实例上调用时接收self
)
顺便说一句,这个BlackMagic
类实例上的in
操作符比以前提出的任何解决方案都要快,或者至少我用我通常的trusty-mtimeit
(直接转到内置方法
,而不是遵循涉及继承和描述符的常规查找路径,从而节省了一点开销)
一个自动执行self.\uuuuu class\uuuuuuu
的元类——每个实例的想法并不难编写(它可以在生成的类的\uuuu new\uuuuuuuuuu
方法中完成繁琐的工作,如果通过\uuuuuu setattr\uuuuuuuuuu>或许多属性在实例上分配,也可以将所有魔法名称设置为实际分配给类)。但只有在对该功能的需求非常广泛的情况下(例如,将大量使用“每实例特殊方法”的大型古代Python 1.5.2项目移植到包括Python 3在内的现代Python中),这才是合理的
我推荐“聪明”或“黑魔法”解决方案吗?不,我不推荐:几乎总是以简单、直接的方式做事情更好。但是“几乎”在这里是一个重要的词,手头有这样先进的“钩子”很好对于极少数但并非不存在的情况,它们的使用可能是有理由的。好吧,这对我来说有一些解释,但对我来说并不完全令人满意,因为这种类型的委托会花费额外的时间(我可以在旧式课程中节省些什么——为什么我不应该使用它们??)“不惜任何代价的表现”不是一个合理的目标:“过早优化是编程中万恶之源”(Knuth,引用Hoare的话)。现代风格的类在功能上更丰富、更通用、更规则、更简单(请参阅“简而言之的Python”第103页的底部,您可以在Google Book Search上读到它——搜索“每实例方法”)。在Python3及更高版本中,遗留类将永远消失-不要将代码绑定到它们以节省微秒的相关性。顺便说一句,更快的方法是从dict继承(这也为您提供了一个新样式的类)。嗨,Alex,感谢编程方面的讲座,我不需要;-)对不起,我们不是圣经学者,所以只需引用一些圣经经文或“大教师“对我来说还不够好。其他解释很好,特别是关于遗留类的解释。我不想坚持旧有的观点,但我要讲道理!同时,我也想到了继承解决方案,它满足了我的特殊问题。不过,在这一点上,旧式类更灵活/更具动态性(特殊方法的每个实例重写在其他情况下也可能很好!)Addon:我的意思是,在速度不是首要原因的情况下,此功能也可能很有用。我喜欢Python的是它的动态性——这在这方面有一点降低。老式的类很粗糙——如果你想要无限制的动态性,Python对你来说不是最佳选择(monkeypatch内置的东西不能像Javascript和Ruby中的那样,等等);相反,我们总是试图平衡好的结构和动态。如果最快速度不是关键问题,那么您总是可以在类上定义特殊方法,并根据需要使其重定向功能。