Чтобы доказать, какой компонент сбой, я бы отслеживал связь TCP / IP с помощью wireshark и смотрел, кто является actaully, закрывающим порт, также могут быть релевантны таймауты.
Перечисления были добавлены в Python 3.4, как описано в PEP 435 . Он также был обратно перенесен в версии 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 и 2.4 на pypi.
Для более продвинутых методов Enum попробуйте библиотеку aenum (2.7, 3.3+, тот же автор, что и enum34
. Код несовместим между py2 и py3, например, вам понадобится __ order __
в python 2 ).
enum34
, выполните $ pip install enum34
aenum
, выполните $ pip install aenum
Установка enum
(без номеров) приведет к установке совершенно другой и несовместимой версии.
from enum import Enum # for enum34, or the stdlib version
# from aenum import Enum # for the aenum version
Animal = Enum('Animal', 'ant bee cat dog')
Animal.ant # returns <Animal.ant: 1>
Animal['ant'] # returns <Animal.ant: 1> (string lookup)
Animal.ant.name # returns 'ant' (inverse lookup)
или эквивалентно:
class Animal(Enum):
ant = 1
bee = 2
cat = 3
dog = 4
В более ранних версиях одним из способов выполнения перечислений является :
def enum(**enums):
return type('Enum', (), enums)
который используется так:
>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'
Вы также можете легко поддерживать автоматическое перечисление, используя что-то вроде этого:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
return type('Enum', (), enums)
и использовать так:
>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1
Поддержка преобразования значений обратно в имена может быть добавлена следующим образом:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
reverse = dict((value, key) for key, value in enums.iteritems())
enums['reverse_mapping'] = reverse
return type('Enum', (), enums)
Это перезаписывает все, что имеет это имя, но это полезно для вывода ваших перечислений. Если обратное сопоставление не существует, это вызовет ошибку KeyError. В первом примере:
>>> Numbers.reverse_mapping['three']
'THREE'
def M_add_class_attribs(attribs):
def foo(name, bases, dict_):
for v, k in attribs:
dict_[k] = v
return type(name, bases, dict_)
return foo
def enum(*names):
class Foo(object):
__metaclass__ = M_add_class_attribs(enumerate(names))
def __setattr__(self, name, value): # this makes it read-only
raise NotImplementedError
return Foo()
Использование это как это:
Animal = enum('DOG', 'CAT')
Animal.DOG # returns 0
Animal.CAT # returns 1
Animal.DOG = 2 # raises NotImplementedError
, если Вы просто хотите уникальные символы и не заботитесь о значениях, заменяете эту строку:
__metaclass__ = M_add_class_attribs(enumerate(names))
с этим:
__metaclass__ = M_add_class_attribs((object(), name) for name in names)
davidg рекомендует использовать dicts. Я пошел бы наборы шага вперед и использования:
months = set('January', 'February', ..., 'December')
Теперь можно протестировать, соответствует ли значение одному из значений в наборе как это:
if m in months:
как dF, тем не менее, я обычно просто использую строковые константы вместо перечислений.
Предложение Alexandru использования констант класса для перечислений работает вполне хорошо.
мне также нравится добавлять словарь для каждого набора констант к поиску человекочитаемое строковое представление.
Это служит двум целям: a) это обеспечивает простой путь к структурной распечатке программы Ваше перечисление и b) словарь логически группирует константы так, чтобы можно было протестировать на членство.
class Animal:
TYPE_DOG = 1
TYPE_CAT = 2
type2str = {
TYPE_DOG: "dog",
TYPE_CAT: "cat"
}
def __init__(self, type_):
assert type_ in self.type2str.keys()
self._type = type_
def __repr__(self):
return "<%s type=%s>" % (
self.__class__.__name__, self.type2str[self._type].upper())
Безопасный с точки зрения типов перечислимый шаблон, который использовался в Java предварительный JDK 5, имеет много преимуществ. Во многом как в ответе Alexandru, Вы создаете класс, и поля уровня класса являются перечислимыми значениями; однако, перечислимые значения являются экземплярами класса, а не маленьких целых чисел. Это имеет преимущество, которое Ваши перечислимые значения непреднамеренно не сравнивают равный маленьким целым числам, можно управлять, как они печатаются, добавьте произвольные методы, если это полезно, и сделайте утверждения с помощью isinstance:
class Animal:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
def __repr__(self):
return "<Animal: %s>" % self
Animal.DOG = Animal("dog")
Animal.CAT = Animal("cat")
>>> x = Animal.DOG
>>> x
<Animal: dog>
>>> x == 1
False
<час> А, недавние , на который поток на python-dev указал там, являются несколькими перечислимыми библиотеками в дикой природе, включая:
При необходимости в числовых значениях вот самый быстрый путь:
dog, cat, rabbit = range(3)
В Python 3.x можно также добавить звездообразного заполнителя в конце, который впитает все остающиеся значения диапазона в случае, если Вы не возражаете тратить впустую память и не можете рассчитать:
dog, cat, rabbit, horse, *_ = range(100)
Это забавно, у меня просто была потребность в этом на днях, и я не мог найти реализацию стоящей использования..., таким образом, я записал свое собственное:
import functools
class EnumValue(object):
def __init__(self,name,value,type):
self.__value=value
self.__name=name
self.Type=type
def __str__(self):
return self.__name
def __repr__(self):#2.6 only... so change to what ever you need...
return '{cls}({0!r},{1!r},{2})'.format(self.__name,self.__value,self.Type.__name__,cls=type(self).__name__)
def __hash__(self):
return hash(self.__value)
def __nonzero__(self):
return bool(self.__value)
def __cmp__(self,other):
if isinstance(other,EnumValue):
return cmp(self.__value,other.__value)
else:
return cmp(self.__value,other)#hopefully their the same type... but who cares?
def __or__(self,other):
if other is None:
return self
elif type(self) is not type(other):
raise TypeError()
return EnumValue('{0.Name} | {1.Name}'.format(self,other),self.Value|other.Value,self.Type)
def __and__(self,other):
if other is None:
return self
elif type(self) is not type(other):
raise TypeError()
return EnumValue('{0.Name} & {1.Name}'.format(self,other),self.Value&other.Value,self.Type)
def __contains__(self,other):
if self.Value==other.Value:
return True
return bool(self&other)
def __invert__(self):
enumerables=self.Type.__enumerables__
return functools.reduce(EnumValue.__or__,(enum for enum in enumerables.itervalues() if enum not in self))
@property
def Name(self):
return self.__name
@property
def Value(self):
return self.__value
class EnumMeta(type):
@staticmethod
def __addToReverseLookup(rev,value,newKeys,nextIter,force=True):
if value in rev:
forced,items=rev.get(value,(force,()) )
if forced and force: #value was forced, so just append
rev[value]=(True,items+newKeys)
elif not forced:#move it to a new spot
next=nextIter.next()
EnumMeta.__addToReverseLookup(rev,next,items,nextIter,False)
rev[value]=(force,newKeys)
else: #not forcing this value
next = nextIter.next()
EnumMeta.__addToReverseLookup(rev,next,newKeys,nextIter,False)
rev[value]=(force,newKeys)
else:#set it and forget it
rev[value]=(force,newKeys)
return value
def __init__(cls,name,bases,atts):
classVars=vars(cls)
enums = classVars.get('__enumerables__',None)
nextIter = getattr(cls,'__nextitr__',itertools.count)()
reverseLookup={}
values={}
if enums is not None:
#build reverse lookup
for item in enums:
if isinstance(item,(tuple,list)):
items=list(item)
value=items.pop()
EnumMeta.__addToReverseLookup(reverseLookup,value,tuple(map(str,items)),nextIter)
else:
value=nextIter.next()
value=EnumMeta.__addToReverseLookup(reverseLookup,value,(str(item),),nextIter,False)#add it to the reverse lookup, but don't force it to that value
#build values and clean up reverse lookup
for value,fkeys in reverseLookup.iteritems():
f,keys=fkeys
for key in keys:
enum=EnumValue(key,value,cls)
setattr(cls,key,enum)
values[key]=enum
reverseLookup[value]=tuple(val for val in values.itervalues() if val.Value == value)
setattr(cls,'__reverseLookup__',reverseLookup)
setattr(cls,'__enumerables__',values)
setattr(cls,'_Max',max([key for key in reverseLookup] or [0]))
return super(EnumMeta,cls).__init__(name,bases,atts)
def __iter__(cls):
for enum in cls.__enumerables__.itervalues():
yield enum
def GetEnumByName(cls,name):
return cls.__enumerables__.get(name,None)
def GetEnumByValue(cls,value):
return cls.__reverseLookup__.get(value,(None,))[0]
class Enum(object):
__metaclass__=EnumMeta
__enumerables__=None
class FlagEnum(Enum):
@staticmethod
def __nextitr__():
yield 0
for val in itertools.count():
yield 2**val
def enum(name,*args):
return EnumMeta(name,(Enum,),dict(__enumerables__=args))
Как хотите, это сделало то, что мне был нужен он, чтобы сделать:)
Использование это как:
class Air(FlagEnum):
__enumerables__=('None','Oxygen','Nitrogen','Hydrogen')
class Mammals(Enum):
__enumerables__=('Bat','Whale',('Dog','Puppy',1),'Cat')
Bool = enum('Bool','Yes',('No',0))
Python не имеет встроенного эквивалента enum
, и другие ответы имеют идеи для реализации Вашего собственного (можно также интересоваться по главной версии в поваренной книге Python).
Однако в ситуациях, где enum
требовался бы в C, я обычно заканчиваю просто простые строки использования : из-за пути реализованы объекты/атрибуты, (C) Python оптимизирован для работы очень быстро с короткими строками так или иначе, таким образом, действительно не было бы никакого выигрыша в производительности к использованию целых чисел. Для принятия мер против опечаток / недопустимые значения, можно вставить регистрации выбранных мест.
ANIMALS = ['cat', 'dog', 'python']
def take_for_a_walk(animal):
assert animal in ANIMALS
...
(Один недостаток по сравнению с использованием класса - то, что Вы теряете преимущество автоматического заполнения)
Hmmm... Я предполагаю, что самой близкой вещью к перечислению был бы словарь, определил любого как это:
months = {
'January': 1,
'February': 2,
...
}
или
months = dict(
January=1,
February=2,
...
)
Затем можно использовать символьное имя для констант как это:
mymonth = months['January']
существуют другие опции, как список кортежей или кортежа кортежей, но словарь является единственным, который предоставляет Вам "символьное" (постоянная строка) способ получить доступ к значению.
Редактирование: Мне нравится ответ Alexandru также!
Перед PEP 435 Python не имел эквивалента, но Вы могли реализовать свое собственное.
Самостоятельно, мне нравится сохранять его простым (я видел некоторые ужасно сложные примеры в сети), что-то вроде этого...
class Animal:
DOG = 1
CAT = 2
x = Animal.DOG
<час> В Python 3.4 ( PEP 435), можно сделать Перечисление базовый класс. Это получает Вас определенная дополнительная функциональность, описанная в PEP. Например, перечислимые участники отличны от целых чисел, и они состоят из name
и value
.
class Animal(Enum):
DOG = 1
CAT = 2
print(Animal.DOG)
# <Animal.DOG: 1>
print(Animal.DOG.value)
# 1
print(Animal.DOG.name)
# "DOG"
<час> , Если Вы не хотите вводить значения, используйте следующий ярлык:
class Animal(Enum):
DOG, CAT = range(2)
<час> Enum
реализации могут быть преобразованы в списки и повторяемы . Порядок его участников является порядком объявления и не имеет никакого отношения к их значениям. Например:
class Animal(Enum):
DOG = 1
CAT = 2
COW = 0
list(Animal)
# [<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.COW: 0>]
[animal.value for animal in Animal]
# [1, 2, 0]
Animal.CAT in Animal
# True
Что я использую:
class Enum(object):
def __init__(self, names, separator=None):
self.names = names.split(separator)
for value, name in enumerate(self.names):
setattr(self, name.upper(), value)
def tuples(self):
return tuple(enumerate(self.names))
, Как использовать:
>>> state = Enum('draft published retracted')
>>> state.DRAFT
0
>>> state.RETRACTED
2
>>> state.FOO
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Enum' object has no attribute 'FOO'
>>> state.tuples()
((0, 'draft'), (1, 'published'), (2, 'retracted'))
, Таким образом, это дает Вам целочисленные константы как состояние. ОПУБЛИКОВАННЫЙ и два кортежа для использования в качестве выбора в моделях Django.
Это просто из-за оптимизации.
Dicts относительно велики.
>>> import sys
>>> sys.getsizeof((lambda:1).__dict__)
140
Большинство (возможно, все) классы, которые определены в C, не имеют dict для оптимизации.
Если вы посмотрите исходный код , вы увидите, что существует множество проверок, чтобы узнать, есть ли у объекта dict или нет.
Вы можете посмотреть рецепт Уилла Уэра для моделирования перечислений в Python , опубликованный в Python Cookbook . Онлайн-версия этого доступна здесь .Дополнительная информация:
PEP 354: Enumerations in Python содержит интересные детали предложения по enum в Python и почему оно было отклонено.
Я прочитал все ответы здесь и прочее в другом месте, и ответ кажется быть ... Не используйте реестр! Неужели это действительно то, что Microsoft хочет, чтобы мы делали с данными конфигурации программы, которые применимы ко всем пользователям!?
Перечисления можно сравнивать друг с другом, но они не имеют особого значения; вы не можете использовать их как целые числа. (Сначала я сопротивлялся этому, потому что я привык к перечислениям C, которые являются целочисленными значениями. Но если вы не можете использовать его как целое число, вы не можете использовать его как целое число по ошибке, поэтому в целом я думаю, что это победа .) Каждое перечисление - уникальное значение. Вы можете печатать перечисления, вы можете перебирать их, вы можете проверить, находится ли значение перечисления «в» перечислении. Это довольно полно и гладко.Edit (cfi): Вышеупомянутая ссылка не совместима с Python 3. Вот мой перенос enum.py на Python 3:
def cmp(a,b):
if a < b: return -1
if b < a: return 1
return 0
def Enum(*names):
##assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!
class EnumClass(object):
__slots__ = names
def __iter__(self): return iter(constants)
def __len__(self): return len(constants)
def __getitem__(self, i): return constants[i]
def __repr__(self): return 'Enum' + str(names)
def __str__(self): return 'enum ' + str(constants)
class EnumValue(object):
__slots__ = ('__value')
def __init__(self, value): self.__value = value
Value = property(lambda self: self.__value)
EnumType = property(lambda self: EnumType)
def __hash__(self): return hash(self.__value)
def __cmp__(self, other):
# C fans might want to remove the following assertion
# to make all enums comparable by ordinal value {;))
assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
return cmp(self.__value, other.__value)
def __lt__(self, other): return self.__cmp__(other) < 0
def __eq__(self, other): return self.__cmp__(other) == 0
def __invert__(self): return constants[maximum - self.__value]
def __nonzero__(self): return bool(self.__value)
def __repr__(self): return str(names[self.__value])
maximum = len(names) - 1
constants = [None] * len(names)
for i, each in enumerate(names):
val = EnumValue(i)
setattr(EnumClass, each, val)
constants[i] = val
constants = tuple(constants)
EnumType = EnumClass()
return EnumType
if __name__ == '__main__':
print( '\n*** Enum Demo ***')
print( '--- Days of week ---')
Days = Enum('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')
print( Days)
print( Days.Mo)
print( Days.Fr)
print( Days.Mo < Days.Fr)
print( list(Days))
for each in Days:
print( 'Day:', each)
print( '--- Yes/No ---')
Confirmation = Enum('No', 'Yes')
answer = Confirmation.No
print( 'Your answer is not', ~answer)
Вот одна реализация:
class Enum(set):
def __getattr__(self, name):
if name in self:
return name
raise AttributeError
Вот его использование:
Animals = Enum(["DOG", "CAT", "HORSE"])
print(Animals.DOG)
Пакет перечислений из PyPI обеспечивает надежную реализацию перечислений. В более раннем ответе упоминался PEP 354; это было отклонено, но предложение было реализовано http://pypi.python.org/pypi/enum .
Использование просто и элегантно:
>>> from enum import Enum
>>> Colors = Enum('red', 'blue', 'green')
>>> shirt_color = Colors.green
>>> shirt_color = Colors[2]
>>> shirt_color > Colors.red
True
>>> shirt_color.index
2
>>> str(shirt_color)
'green'
Use the following.
TYPE = {'EAN13': u'EAN-13',
'CODE39': u'Code 39',
'CODE128': u'Code 128',
'i25': u'Interleaved 2 of 5',}
>>> TYPE.items()
[('EAN13', u'EAN-13'), ('i25', u'Interleaved 2 of 5'), ('CODE39', u'Code 39'), ('CODE128', u'Code 128')]
>>> TYPE.keys()
['EAN13', 'i25', 'CODE39', 'CODE128']
>>> TYPE.values()
[u'EAN-13', u'Interleaved 2 of 5', u'Code 39', u'Code 128']
I used that for Django model choices, and it looks very pythonic. It is not really an Enum, but it does the job.
Мне потребовались некоторые символические константы в pyparsing для представления левой и правой ассоциативности бинарных операторов. Я использовал такие константы класса:
# an internal class, not intended to be seen by client code
class _Constants(object):
pass
# an enumeration of constants for operator associativity
opAssoc = _Constants()
opAssoc.LEFT = object()
opAssoc.RIGHT = object()
Теперь, когда клиентский код хочет использовать эти константы, они могут импортировать все перечисление, используя:
import opAssoc from pyparsing
Перечисления уникальны, их можно протестировать с помощью 'is' вместо '==' , они не занимают много места в моем коде из-за второстепенной концепции и легко импортируются в клиентский код. Они не поддерживают какое-либо необычное поведение str (), но пока это относится к категории YAGNI .
Следуя Java-подобной реализации enum, предложенной Аароном Маенпаа, я сделал следующее. Идея заключалась в том, чтобы сделать его универсальным и доступным для анализа.
class Enum:
#'''
#Java like implementation for enums.
#
#Usage:
#class Tool(Enum): name = 'Tool'
#Tool.DRILL = Tool.register('drill')
#Tool.HAMMER = Tool.register('hammer')
#Tool.WRENCH = Tool.register('wrench')
#'''
name = 'Enum' # Enum name
_reg = dict([]) # Enum registered values
@classmethod
def register(cls, value):
#'''
#Registers a new value in this enum.
#
#@param value: New enum value.
#
#@return: New value wrapper instance.
#'''
inst = cls(value)
cls._reg[value] = inst
return inst
@classmethod
def parse(cls, value):
#'''
#Parses a value, returning the enum instance.
#
#@param value: Enum value.
#
#@return: Value corresp instance.
#'''
return cls._reg.get(value)
def __init__(self, value):
#'''
#Constructor (only for internal use).
#'''
self.value = value
def __str__(self):
#'''
#str() overload.
#'''
return self.value
def __repr__(self):
#'''
#repr() overload.
#'''
return "<" + self.name + ": " + self.value + ">"
Почему перечисления должны быть целыми числами? К сожалению, я не могу придумать какую-либо красивую конструкцию для создания этого без изменения языка Python, поэтому я буду использовать строки:
class Enumerator(object):
def __init__(self, name):
self.name = name
def __eq__(self, other):
if self.name == other:
return True
return self is other
def __ne__(self, other):
if self.name != other:
return False
return self is other
def __repr__(self):
return 'Enumerator({0})'.format(self.name)
def __str__(self):
return self.name
class Enum(object):
def __init__(self, *enumerators):
for e in enumerators:
setattr(self, e, Enumerator(e))
def __getitem__(self, key):
return getattr(self, key)
Опять же, может быть, теперь даже лучше, когда мы можем естественным образом тестировать строки, ради файлы конфигурации или другой удаленный ввод.
Пример:
class Cow(object):
State = Enum(
'standing',
'walking',
'eating',
'mooing',
'sleeping',
'dead',
'dying'
)
state = State.standing
In [1]: from enum import Enum
In [2]: c = Cow()
In [3]: c2 = Cow()
In [4]: c.state, c2.state
Out[4]: (Enumerator(standing), Enumerator(standing))
In [5]: c.state == c2.state
Out[5]: True
In [6]: c.State.mooing
Out[6]: Enumerator(mooing)
In [7]: c.State['mooing']
Out[7]: Enumerator(mooing)
In [8]: c.state = Cow.State.dead
In [9]: c.state == c2.state
Out[9]: False
In [10]: c.state == Cow.State.dead
Out[10]: True
In [11]: c.state == 'dead'
Out[11]: True
In [12]: c.state == Cow.State['dead']
Out[11]: True
def enum( *names ):
'''
Makes enum.
Usage:
E = enum( 'YOUR', 'KEYS', 'HERE' )
print( E.HERE )
'''
class Enum():
pass
for index, name in enumerate( names ):
setattr( Enum, name, index )
return Enum
Мне нравится перечисление Java , вот как я это делаю в Python:
def enum(clsdef):
class Enum(object):
__slots__=tuple([var for var in clsdef.__dict__ if isinstance((getattr(clsdef, var)), tuple) and not var.startswith('__')])
def __new__(cls, *args, **kwargs):
if not '_the_instance' in cls.__dict__:
cls._the_instance = object.__new__(cls, *args, **kwargs)
return cls._the_instance
def __init__(self):
clsdef.values=lambda cls, e=Enum: e.values()
clsdef.valueOf=lambda cls, n, e=self: e.valueOf(n)
for ordinal, key in enumerate(self.__class__.__slots__):
args=getattr(clsdef, key)
instance=clsdef(*args)
instance._name=key
instance._ordinal=ordinal
setattr(self, key, instance)
@classmethod
def values(cls):
if not hasattr(cls, '_values'):
cls._values=[getattr(cls, name) for name in cls.__slots__]
return cls._values
def valueOf(self, name):
return getattr(self, name)
def __repr__(self):
return ''.join(['<class Enum (', clsdef.__name__, ') at ', str(hex(id(self))), '>'])
return Enum()
Пример использования:
i=2
@enum
class Test(object):
A=("a",1)
B=("b",)
C=("c",2)
D=tuple()
E=("e",3)
while True:
try:
F, G, H, I, J, K, L, M, N, O=[tuple() for _ in range(i)]
break;
except ValueError:
i+=1
def __init__(self, name="default", aparam=0):
self.name=name
self.avalue=aparam
Все переменные класса определены как кортежи, как и конструктор. Пока вы не можете использовать именованные аргументы.