在子类化枚举上从PEP 435开始,允许以下内容:
>>> class Foo(Enum):
... def some_behavior(self):
... pass
...
>>> class Bar(Foo):
... happy = 1
... sad = 2
...
我想以some_behavior
和happy
枚举的不同方式定义sad
。
有没有更好的方法来做到这一点:
>>> class Bar(Foo):
... happy = 1
... sad = 2
... def some_behavior(self):
... if self is Bar.happy:
... # happy behavior
... elif self is Bar.sad:
... # sad behavior
对我来说这看起来很笨拙。
答案 0 :(得分:3)
不,没有。
我的意思是,你可能会做这样的事情:
def some_behavior(self):
return {Bar.happy: some_function
Bar.sad: some_other_function}[self](arguments?)
或者像这样:
def some_behavior(self):
custom_thing = {Bar.happy: some_function
Bar.sad: some_other_function}[self]
# do something which is the same for both
custom_thing()
# do something else the same for both
但是除非已经存在some_function
等,否则这可能不会比你现在拥有的要好得多(尽管你可能能够保存一两级缩进,我想)。你可以在这里使用lambdas,但是这很快就会变得难看,除了最简单的情况之外我不推荐它(通常可以用functools.partial
处理)。
正如评论中所讨论的,可以执行以下操作:
class Foo(Enum):
happy = 1
sad = 2
def happy_behavior(): # No self argument!
self = Foo.happy # only if you need self
...
def sad_behavior():
self = Foo.sad
...
Foo.happy.some_behavior = happy_behavior
Foo.sad.some_behavior = sad_behavior
在我看来,这是相当丑陋的,但它应该适用于所有合理的情况,包括Foo(1).some_behavior()
或Foo['sad'].some_behavior()
等表达式。但是,它可能会混淆静态类型的检查器和/或短路。
答案 1 :(得分:0)
是的,有 1 。
诀窍在于覆盖__getattribute__
,该拦截会拦截所有名称查找,并且非常危险 2 :
class Foo(Enum):
def __getattribute__(self, name):
# overriding this method is dangerous!
#
# enum member value must be an instance of a class
value_dict = super().__getattribute__('_value_').__class__.__dict__
if name in value_dict:
# bind the enum member instance to the method and return it
return partial(value_dict[name], self)
else:
# otherwise return the found object unchanged
return super().__getattribute__(name)
def __repr__(self):
# clean up the repr()
return '<%s.%s>' % (self.__class__.__name__, self.name)
添加一个小助手功能:
def member(cls):
# convert the class into an instance of itself
return cls()
然后写下最后的Enum
:
class Bar(Foo):
#
# default methods
#
def some_behavior(self):
return self.name + ' is neutral'
def likes_to(self):
return 'likes to sit'
#
# members
#
@member
class happy:
# overridden methods
def some_behavior(self):
return self.name + ' is happy'
def likes_to(self):
return 'likes to dance'
@member
class sad:
# overridden method
def some_behavior(self):
return self.name + ' is sad'
@member
class okay:
# uses default methods
pass
正在使用:
>>> list(Bar)
[<Bar.happy>, <Bar.sad>, <Bar.okay>]
>>> Bar.happy.some_behavior()
'happy is happy'
>>> Bar.happy.likes_to()
'likes to dance'
>>> Bar.sad.some_behavior()
'sad is sad'
>>> Bar.sad.likes_to()
'likes to sit'
>>> Bar.okay.some_behavior()
'okay is neutral'
>>> Bar.okay.likes_to()
'likes to sit'
1 绝对不是惯用语。
2 覆盖__getattribute__
很危险,因为它控制属性的处理方式-例如,在object.__getattribute__
中实现描述符魔术。这里的任何错误都可能导致难以调试的问题
披露:我是Python stdlib Enum
,enum34
backport和Advanced Enumeration (aenum
)库的作者。