2016-11-17 4 views
2

Это несколько следующее: Why are mutable values in Python Enums the same object?.Почему допустимы переменные значения в Python Enums?

Если значения Enum являются изменяемыми (например, list s и т. Д.), Эти значения могут быть изменены в любое время. Я думаю, что это создает что-то вопрос, если Enum члены извлекаются значения, особенно если кто-то неосторожно изменяет значение в Enum он смотрит вверх:

>>> from enum import Enum 
>>> class Color(Enum): 
     black = [1,2] 
     blue = [1,2,3] 

>>> val_1 = [1,2] 
>>> val_2 = [1,2,3] 
>>> Color(val_1) 
<Color.black: [1, 2]> 
>>> Color(val_2) 
<Color.blue: [1, 2, 3]> 
>>> my_color = Color(val_1) 
>>> my_color.value.append(3) 
>>> Color(val_2) 
<Color.black: [1, 2, 3]> 
>>> Color(val_1) 
Traceback (most recent call last): 
    ... 
ValueError: [1, 2] is not a valid Color 

Я думаю, учитывая нормальные идиомы Python это хорошо, с подразумевая, что пользователи могут использовать переменные как их значения Enum, но просто для понимания банки червей, которые они могут открывать.

Однако это вызывает второй вопрос - так как вы можете посмотреть в Enum memeber по значению, а значение может быть изменяемым, то он должен быть делать поиск средством иным, чем HashMap/dict, так как изменяемые не может быть key в таком dict.

Не было бы более эффективным (хотя, предоставлено, менее гибким) ограничить значения Enum только изменчивыми типами, чтобы поиск по значению мог быть реализован с помощью dict?

ответ

1

Похоже, что ответ на мой второй вопрос был скрыт на виду в сурровом коде для enum.py.

Каждый Enumделает содержат dict из value->member пар для hashable (т.е. неизменных) значений, и когда смотришь вверх по Enum по значению, он пытается извлечь элемент из этого dict. Если значение не равно hashable, то тогда грубая сила сравнивается для равенства по отношению ко всем существующим значениям Enum, возвращая член, если находит совпадение. Соответствующий код находится в строках 468-476 в enum.py:

try: 
    if value in cls._value2member_map_: 
     return cls._value2member_map_[value] 
except TypeError: 
    # not there, now do long search -- O(n) behavior 
    for member in cls._member_map_.values(): 
     if member._value_ == value: 
      return member 
raise ValueError("%r is not a valid %s" % (value, cls.__name__)) 

Так что кажется, будто дизайнеры enum.py хотели иметь быстрый поиск при получении Enum сек по значению, но все же хотел дать гибкость, имеющие изменяемые значения для значений Enum (хотя я до сих пор не могу придумать причину , почему кто-то хотел бы этого в первую очередь).

Смежные вопросы