覆盖类的 __contains__ 方法 [英] Overriding __contains__ method for a class
问题描述
我需要在 Python 中模拟枚举,并通过编写如下类来实现:
类垃圾邮件(枚举):k = 3鸡蛋 = 0火腿 = 1烤豆 = 2
现在我想使用以下语法测试某些常量是否是特定 Enum 派生类的有效选择:
if (x in Foo):打印(看起来合法")
因此,我尝试创建一个Enum"基类,在其中覆盖 __contains__
方法,如下所示:
类枚举:"""模拟一个枚举."""k = 0 # 在子类中用常量数覆盖@类方法def __contains__(cls, x):"""测试有效的枚举常量 x:枚举中的 x"""返回(范围内的x(cls.k))
但是,在类上使用 in
关键字时(如上面的示例),我收到错误:
TypeError: 'type' 类型的参数不可迭代
为什么?我能以某种方式获得我想要的语法糖吗?
为什么会这样?
当您使用像 a in Foo
这样的特殊语法时,__contains__
方法会根据 Foo
的类型查找.但是,您的 __contains__
实现存在于 Foo
本身,而不是它的类型.Foo
的类型是 type
,它没有实现这个(或迭代),因此错误.
如果您实例化一个对象,然后在创建对象后,将一个 __contains__
函数添加到实例变量中,也会发生同样的情况.不会调用该函数:
<块引用>
我能以某种方式获得我想要的语法糖吗?
是的.如上所述,该方法是根据 Foo
的类型查找的.类的类型称为元类,因此您需要一个实现 __contains__
的新元类.
试试这个:
class MetaEnum(type):def __contains__(cls, x):返回范围内的 x(cls.k)
如您所见,元类上的方法将元类实例——类——作为它们的第一个参数.这应该是有道理的.它与类方法非常相似,只是方法存在于元类而不是类中.
从具有自定义元类的类继承也会继承元类,因此您可以像这样创建基类:
class BaseEnum(metaclass=MetaEnum):经过类 MyEnum(BaseEnum):k = 3打印(MyEnum 中的 1)# 真
I need to simulate enums in Python, and did it by writing classes like:
class Spam(Enum):
k = 3
EGGS = 0
HAM = 1
BAKEDBEANS = 2
Now I'd like to test if some constant is a valid choice for a particular Enum-derived class, with the following syntax:
if (x in Foo):
print("seems legit")
Therefore I tried to create an "Enum" base class where I override the __contains__
method like this:
class Enum:
"""
Simulates an enum.
"""
k = 0 # overwrite in subclass with number of constants
@classmethod
def __contains__(cls, x):
"""
Test for valid enum constant x:
x in Enum
"""
return (x in range(cls.k))
However, when using the in
keyword on the class (like the example above), I get the error:
TypeError: argument of type 'type' is not iterable
Why that? Can I somehow get the syntactic sugar I want?
Why that?
When you use special syntax like a in Foo
, the __contains__
method is looked up on the type of Foo
. However, your __contains__
implementation exists on Foo
itself, not its type. Foo
's type is type
, which doesn't implement this (or iteration), thus the error.
The same situation occurs if you instantiate an object and then, after it is created, add a __contains__
function to the instance variables. That function won't be called:
>>> class Empty: pass
...
>>> x = Empty()
>>> x.__contains__ = lambda: True
>>> 1 in x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: argument of type 'Empty' is not iterable
Can I somehow get the syntactic sugar I want?
Yes. As mentioned above, the method is looked up on Foo
's type. The type of a class is called a metaclass, so you need a new metaclass that implements __contains__
.
Try this one:
class MetaEnum(type):
def __contains__(cls, x):
return x in range(cls.k)
As you can see, the methods on a metaclass take the metaclass instance -- the class -- as their first argument. This should make sense. It's very similar to a classmethod, except that the method lives on the metaclass and not the class.
Inheritance from a class with a custom metaclass also inherits the metaclass, so you can create a base class like so:
class BaseEnum(metaclass=MetaEnum):
pass
class MyEnum(BaseEnum):
k = 3
print(1 in MyEnum) # True
这篇关于覆盖类的 __contains__ 方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!