在Python中模拟成员资格测试:将__contains__正确委派给包含对象 [英] Emulating membership-test in Python: delegating __contains__ to contained-object correctly

查看:124
本文介绍了在Python中模拟成员资格测试:将__contains__正确委派给包含对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经习惯了Python允许一些巧妙的技巧来将功能委托给其他对象。一个示例是委派包含对象。

I am used to that Python allows some neat tricks to delegate functionality to other objects. One example is delegation to contained objects.

但是当我想委派__contains __时,它似乎没有运气:

But it seams, that I don't have luck, when I want to 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 .__包含__(1)时,一切都会顺利进行。我什至尝试在A中定义__iter __方法,以使A看起来更像是一个可迭代的对象,但这无济于事。我在这里错过了什么?

What I am making wrong? When I call a.__contains __(1), everything goes smooth. I even tried to define an __iter __ method in A to make A more look like an iterable, but it did not help. What I am missing out here?

推荐答案

特殊方法,例如 __ contains __ 仅当在类上定义时才是特殊的,而不是在实例上定义时才是特殊的(Python 2中的旧类除外,无论如何您都应该使用它们)。

Special methods such as __contains__ are only special when defined on the class, not on the instance (except in legacy classes in Python 2, which you should not use anyway).

所以,您的代表团是在班级吗?

So, do your delegation at class level:

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

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

我实际上更愿意将后者拼写为 return other in self.mydict ,但是

I'd actually prefer to spell the latter as return other in self.mydict, but that's a minor style issue.

编辑:是否以及何时完全动态按实例重定向特殊方法(例如旧式类)提供)是必不可少的,使用新型类来实现它并不难:您只需要将具有特殊功能的每个实例包装在自己的特殊类中即可。例如:

Edit: if and when "totally dynamic per-instance redirecting of special methods" (like old-style classes offered) is indispensable, it's not hard to implement it with new-style classes: you just need each instance that has such peculiar need to be wrapped in its own special class. For example:

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

Essentially, after the little bit of black magic reassigning self.__class__ to a new class object (which behaves just like the previous one but has an empty dict and no other instances except this one self), anywhere in an old-style class you would assign to self.__magicname__, assign to self.__class__.__magicname__ instead (and make sure it's a built-in or staticmethod, not a normal Python function, unless of course in some different case you do want it to receive the self when called on the instance).

偶然地,在 BlackMagic实例上的 in 运算符类比以前提出的任何解决方案都要快 ,或者至少我是用我通常信任的 -mtimeit (直接转到内置方法,而不是遵循涉及继承和描述符的常规查找路径,可以节省一些开销)。

Incidentally, the in operator on an instance of this BlackMagic class is faster, as it happens, than with any of the previously proposed solutions -- or at least so I'm measuring with my usual trusty -mtimeit (going directly to the built-in method, instead of following normal lookup routes involving inheritance and descriptors, shaves a bit of the overhead).

一个用于自动完成 self的元类。__class __ -每个实例的想法很容易编写(它可以生成的类的 __ new __ 方法中的脏工作,并且还可以设置所有魔术名称,以便在实例上分配时实际上分配给该类,可以通过 __ setattr__ 或许多许多属性)。但这只有在真正需要此功能的情况下才是合理的(例如,将庞大的古老的Python 1.5.2项目移植到现代Python(包括Python 3)中,该项目自由地使用按实例的特殊方法。

A metaclass to automate the self.__class__-per-instance idea would not be hard to write (it could do the dirty work in the generated class's __new__ method, and maybe also set all magic names to actually assign on the class if assigned on the instance, either via __setattr__ or many, many properties). But that would be justified only if the need for this feature was really widespread (e.g. porting a huge ancient Python 1.5.2 project that liberally use "per-instance special methods" to modern Python, including Python 3).

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

Do I recommend "clever" or "black magic" solutions? No, I don't: almost invariably it's better to do things in simple, straightforward ways. But "almost" is an important word here, and it's nice to have at hand such advanced "hooks" for the rare, but not non-existent, situations where their use may actually be warranted.

这篇关于在Python中模拟成员资格测试:将__contains__正确委派给包含对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆