在Alec Thomas的this answer之后,我使用以下内容创建枚举:
def enum(*sequential):
enums = dict(zip(sequential, range(len(sequential))))
return type('Enum', (), enums)
我希望能够获得其中一个枚举的长度。例如,我可以写
>>> Suit = enum('spades', 'hearts', 'diamonds', 'clubs')
>>> Suit.spades
0
>>> Suit.hearts
1
>>> Suit.diamonds
2
>>> Suit.clubs
3
但是没有办法在运行时列出所有枚举值。我希望能够做一些像
这样的事情>>> [s for s in Suit]
[0, 1, 2, 3]
我尝试在enum['__iter__']
函数中分配enum()
,但我不知道需要分配哪种对象:
def enum(*sequential):
enums = dict(zip(sequential, range(len(sequential))))
enums['__iter__'] = iter(range(len(sequential)))
return type('Enum', (), enums)
给出
>>> [s for s in Suit]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'type' object is not iterable
如何让enum
能够列出其成员? (即使只是enum报告其长度的能力就足够了,因为那时成员只是range(len(Suit))
的元素。)
答案 0 :(得分:7)
问题是type(…)
返回类型,即实际用于创建对象的内容。当然,你可以争论这是否是一个问题 - 而且可能不是因为Python的打字系统如何工作(一切都是对象,类型只是type
对象的对象等。)。
然而,效果是您无法添加特殊方法,例如在这种情况下需要的__iter__
。然而,在对象的类型上查找特殊方法,因此在type
上(这是您正在创建的类型的基本类型)。 type
- 正如您所期望的那样 - 不可迭代。
因此,如果你想要一些可迭代的东西,你需要创建一个非类型的东西。你可能会在这里提出一些奇特的元类,但是你能做的最简单的事情,也就是你的代码保持相同的长度,实际上是named tuple。这是顺便说一句。另外,Python 3.4 enum
type中的语义也受到启发。
>>> def enum(*keys):
return namedtuple('Enum', keys)(*range(len(keys)))
>>> Suit = enum('spades', 'hearts', 'diamonds', 'clubs')
>>> Suit.spades
0
>>> Suit.hearts
1
>>> Suit.diamonds
2
>>> Suit.clubs
3
>>> [s for s in Suit]
[0, 1, 2, 3]
答案 1 :(得分:4)
我建议您使用collections.namedtuple
使用enumerator
的其他实现方式
<强>实施强>
>>> from collections import namedtuple
>>> def enum(*sequential):
enums = namedtuple('enums',sequential)(*range(len(sequential)))
return enums
<强>用法强>
>>> Suit = enum('spades', 'hearts', 'diamonds', 'clubs')
>>> Suit.spades
0
>>> Suit.hearts
1
>>> Suit.diamonds
2
>>> Suit.clubs
3
>>> [s for s in Suit]
[0, 1, 2, 3]
答案 2 :(得分:3)
这似乎符合您的要求:
def enum(*sequential):
length = len(sequential)
pairs = zip(sequential, xrange(len(sequential)))
Enum = type('Enum', (), dict(pairs))
Enum.__len__ = lambda _: length
Enum.__iter__ = lambda _: iter(range(length))
return Enum()
Suit = enum('spades', 'hearts', 'diamonds', 'clubs')
print Suit.spades # 0
print Suit.hearts # 1
print Suit.diamonds # 2
print Suit.clubs # 3
print 'len(Suit):', len(Suit) # len(Suit): 4
print [s for s in Suit] # [0, 1, 2, 3]
答案 3 :(得分:1)
你的变体有效!在()
之后添加type(...)
以创建类实例并修改__iter__
:
def enum(*sequential):
enums = dict(zip(sequential, range(len(sequential))))
enums['__iter__'] = lambda e,i=iter(range(len(sequential))): i
return type('Enum', (object,), enums)()
>>> suit = enum('spades', 'hearts', 'diamonds', 'clubs')
>>> [s for s in suit]
[0, 1, 2, 3]