我正在尝试为Node
类创建一组状态。通常,我会通过将每个Node
实例的state
变量设置为int
来执行此操作,并记录哪个int对应于哪个状态(因为我没有enum
s )。
这一次,我想尝试不同的东西,所以我决定采用这个:
class Node:
state1 = 1
state2 = 2
def __init__(self):
...
这很有效。但是,我遇到了一个问题,我有很多状态 - 手动输出太多了。此外,在许多状态下,我可能会出错并将相同的int
分配给两个状态。在测试状态时,这将成为错误的来源(例如:if self.state==Node.state1
可能会失败,如果Node.state1
和Node.state2
都是3
)。
出于这个原因,我想做这样的事情:
class Node:
def __init__(self):
...
...
for i,state in enumerate("state1 state2".split()):
setattr(Node, state, i)
虽然这可以解决将值分配给状态时的人为错误,但它非常难看,因为类变量是在类定义之外设置的。
有没有办法以这种方式在类定义中设置类变量?我最好这样做:
class Node:
for i,state in enumerate("state1 state2".split()):
setattr(Node, state, i)
...但由于Node
尚未定义,因此无效,并且会产生NameError
或者,python3.3中是否存在enum
?
我正在使用Python3.3.2,如果重要的话
答案 0 :(得分:3)
现在Python有Enum
类型,没有理由不使用它。有这么多州,我建议使用有记录的AutoEnum。像这样:
class Node:
class State(AutoEnum):
state1 = "initial state before blah"
state2 = "after frobbing the glitz"
state3 = "still needs the spam"
state4 = "now good to go"
state5 = "gone and went"
vars().update(State.__members__)
然后在使用中:
--> Node.state2
<State.state2: 2>
注意:链接的配方适用于Python 2.x - 您需要删除unicode
引用才能使其在Python 3.x中运行。
答案 1 :(得分:2)
有enum34: Python 3.4 Enum backported
>>> import enum
>>> State = enum.IntEnum('State', 'state1 state2')
>>> State.state1
<State.state1: 1>
>>> State.state2
<State.state2: 2>
>>> int(State.state2)
2
使用AutoNumber
from Python 3.4 enum documentation:
>>> import enum
>>> class AutoNumber(enum.Enum):
... def __new__(cls):
... value = len(cls.__members__) + 1
... obj = object.__new__(cls)
... obj._value_ = value
... return obj
...
>>> class Node(AutoNumber):
... state1 = ()
... state2 = ()
...
>>> Node.state1
<Node.state1: 1>
>>> Node.state2
<Node.state2: 2>
>>> Node.state2.value
2
答案 2 :(得分:2)
如果您在课程定义之后执行setattr
的唯一问题是它丑陋而且位置错误,那么使用装饰器来做这件事呢?
def add_constants(names):
def adder(cls):
for i, name in enumerate(names):
setattr(cls, name, i)
return cls
return adder
@add_constants("state1 state2".split())
class Node:
pass
答案 3 :(得分:1)
有多种方法可以做到这一点,我想说最明显的一种方法是使用元类,但移动你的for循环1缩进级别也会有效。
关于枚举的存在:http://docs.python.org/3.4/library/enum.html
这是一个元类示例:
class EnumMeta(type):
def __new__(cls, name, bases, dict_):
names = dict_.get('_enum_string', '')
if names:
for i, name in enumerate(names.split()):
dict_[name] = 'foo %d' % i
return super(EnumMeta, cls).__new__(cls, name, bases, dict_)
class Node(object):
__metaclass__ = EnumMeta
_enum_string = 'state1 state2'
print 'state1', SomeMeta.state1
print 'state2', SomeMeta.state2
或带有循环的简单版本(但丑陋的imho,而且不太灵活):
class Node(object):
pass
for i, state in enumerate('state1 state2'.split()):
setattr(Node, state, i)
答案 4 :(得分:1)
有没有办法以这种方式在类定义中设置类变量?我最好这样做:
class Node:
for i,state in enumerate("state1 state2".split()):
setattr(Node, state, i)
...但由于Node尚未定义,因此无法正常工作,并且会导致NameError
虽然该类尚不存在,但它所使用的命名空间仍然存在。可以使用vars()
(我认为locals()
)访问它。这意味着您可以执行以下操作:
class Node:
node_namespace = vars()
for i, state in enumerate('state1 state2'.split()):
node_namespace[state] = i
del node_namespace