Python enum.Enum
的声明性用法需要提供值,当在enum的最基本用例中,我们实际上并不关心名称和值。我们只关心哨兵本身。在最近阅读了related Q&A之后,我意识到可以使用枚举的元类的__prepare__
方法来获得这种声明:
class Color(Enum):
red
blue
green
让事情变得如此干燥的实施实际上相当容易:
from collections import defaultdict
class EnumMeta(type):
@classmethod
def __prepare__(meta, name, bases):
return defaultdict(object)
def __new__(cls, name, bases, classdict):
classdict.default_factory = None
return type.__new__(cls, name, bases, classdict)
class Enum(metaclass=EnumMeta):
pass
在Python 3.6中,提供enum.auto
来帮助解决omitting values的问题,但界面仍然很奇怪 - 您需要为auto()
指定__repr__
值每个成员,并从另一个基础继承,以修复class Color(NoValue):
red = auto()
blue = auto()
green = auto()
:
auto
知道为标准库选择的实现已经进入了许多工时和非常小心,必须有一些理由为什么早先演示的声明性枚举的更多Pythonic版本无法正常工作。
我的问题是,提出的方法有哪些问题和失败模式,为什么这个(或类似的东西)决定反对 - 而Python中包含def __init__(self, state_size, question_tensor, encoded_questions, batch_size):
self._state_size = state_size
self.question_tensor = question_tensor
self.encoded_questions = encoded_questions
self.batch_size = batch_size
@property
def state_size(self):
return self._state_size
@property
def output_size(self):
return self._state_size
def __call__(self, inputs, state, scope=None):
scope = scope or type(self).__name__
with tf.variable_scope(scope):
W_p = tf.get_variable("W_p", dtype=tf.float64, shape=[self.state_size, self.state_size], initializer=tf.contrib.layers.xavier_initializer())
W_r = tf.get_variable("W_r", dtype=tf.float64, shape=[self.state_size, self.state_size], initializer=tf.contrib.layers.xavier_initializer())
b_p = tf.get_variable("b_p", dtype=tf.float64, shape=[self.state_size])
w = tf.get_variable("w", dtype=tf.float64, shape=[1,self.state_size])
b = tf.get_variable("b", dtype=tf.float64, shape=[])
#print 'question tensor', np.shape(self.question_tensor)
#print 'inputs', np.shape(inputs)
#print 'insides', np.shape(tf.matmul(inputs, W_p) + tf.matmul(state, W_r) + b_p)
G = tf.nn.tanh(
tf.transpose(tf.transpose(self.question_tensor, perm=[1,0,2]) +
(tf.matmul(inputs, W_p) + tf.matmul(state, W_r) + b_p), perm=[1,0,2])
)
#print 'big G', np.shape(G)
attention_list = []
for i in range(self.batch_size):
attention_matrix = tf.matmul(G[i,:,:], tf.transpose(w))
attention_list.append(attention_matrix)
attention_scores = tf.stack(attention_list)
a = tf.nn.softmax(attention_scores + b)
a = tf.reshape(a, [self.batch_size, -1])
#print 'a shape is', np.shape(a)
weighted_question_list = []
for i in range(self.batch_size):
attention_vector = tf.matmul(tf.reshape(a[i], [1,-1]), self.encoded_questions[i])
weighted_question_list.append(attention_vector)
weighted_questions = tf.stack(weighted_question_list)
weighted_questions = tf.reshape(weighted_questions, [32, -1])
#print'weighted questions', np.shape(weighted_questions)
z = tf.concat([inputs, weighted_questions], 1)
lstm_cell = tf.nn.rnn_cell.LSTMCell(self.state_size)
output, new_state = lstm_cell.__call__(z, state)
return output, new_state
功能呢?
答案 0 :(得分:7)
让defaultdict
成为Enum的命名空间有几个陷阱:
_EnumDict
命名空间中丢失保护:
_generate
方法最重要的是:
为什么它会起作用? __prepare__
不仅可以在命名空间dict上设置属性,因此命名空间也可以自行命令 - 而_EnumDict
可以:_member_names
,列出应该是成员的所有属性。
但是,声明一个没有值的名称的目标并非不可能 - aenum
1 包允许它有一些安全措施:
property
,classmethod
和staticmethod
,但可以包含它们和/或排除其他全局名称这种行为对于stdlib来说被认为太神奇了,所以如果你想要它,以及其他一些增强/改进 2 ,你必须使用aenum
一个例子:
from aenum import AutoEnum
class Color(AutoEnum):
red
green
blue
__repr__
仍显示创建的值。
-
1 披露:我是Python stdlib Enum
,enum34
backport和Advanced Enumeration (aenum
)图书馆的作者。
2 NamedConstant
(就像它说的那样;),NamedTuple
(基于元类,默认值等),加上一些内置枚举:
MultiValueEnum
- >多个值可以映射到一个名称(而不是别名)NoAliasEnum
- >具有相同值的名称不是别名(想想扑克牌)OrderedEnum
- >成员按定义可比较订单UniqueEnum
- >没有别名允许答案 1 :(得分:1)
您可能感兴趣的是可以使用多个参数创建枚举:
from enum import Enum
class NoValue(Enum):
def __repr__(self):
return '<%s.%s>' % (self.__class__.__name__, self.name)
Color = NoValue('Color', ['red', 'green', 'blue']) # no need for "auto()" calls
这样您就不必使用auto
或其他任何内容(例如__prepare__
)。
为什么这个(或类似的东西)决定反对 - 而自动功能包含在Python 3.6中呢?
已经在Python问题跟踪器(特别是bpo-23591)上对此进行了详细讨论,并且我将包含针对它的(汇总的)参数:
这是一个基本的东西:它打破了类主体是一套命令的承诺,其中Python语句(例如赋值)具有它们通常的语义。
只要[auto]已在某处定义(即来自enum import [auto]),它就是普通的Python,并且不与其他语言或其工具链作斗争。
简而言之:类定义将这些“变量”解释为查找:
class A(object):
a
但是对于enum
,它们应该被解释为赋值?该用例根本不被视为"special enough to break the rules"。