Yanıtlar:
PEP 435'te açıklandığı gibi numaralandırmalar Python 3.4'e eklenmiştir . Ayrıca, pypi üzerinde 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 ve 2.4'e rapor edilmiştir.
Daha gelişmiş Enum teknikleri için aenum kütüphanesini deneyin (2.7, 3.3+, aynı yazar enum34
. Kod py2 ve py3 arasında mükemmel uyumlu değildir, örneğin __order__
python 2'de ihtiyacınız olacak ).
enum34
, do$ pip install enum34
aenum
, do$ pip install aenum
Yükleme enum
(numara yok) tamamen farklı ve uyumsuz bir sürüm yükler.
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)
Veya eşdeğer olarak:
class Animal(Enum):
ant = 1
bee = 2
cat = 3
dog = 4
Önceki sürümlerde, numaralandırmayı gerçekleştirmenin bir yolu:
def enum(**enums):
return type('Enum', (), enums)
Bu şekilde kullanılır:
>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'
Ayrıca otomatik numaralandırmayı aşağıdaki gibi bir şeyle kolayca destekleyebilirsiniz:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
return type('Enum', (), enums)
ve şu şekilde kullanılır:
>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1
Değerleri tekrar isimlere dönüştürme desteği şu şekilde eklenebilir:
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)
Bu, bu ada sahip herhangi bir şeyin üzerine yazar, ancak numaralarınızı çıktıda oluşturmak için kullanışlıdır. Ters eşleme yoksa KeyError atar. İlk örnekle:
>>> Numbers.reverse_mapping['three']
'THREE'
**named
Eski sürümler için numaralandırma işlevindeki var kwargs ( ) özel değerleri desteklemektir:enum("blue", "red", "green", black=0)
PEP 435'ten önce, Python'un eşdeğeri yoktu ama kendinizinkini uygulayabilirsiniz.
Kendimi, basit tutmayı seviyorum (internette korkunç karmaşık örnekler gördüm), böyle bir şey ...
class Animal:
DOG = 1
CAT = 2
x = Animal.DOG
Python 3.4'te ( PEP 435 ), Enum'u temel sınıf yapabilirsiniz. Bu size PEP'te açıklanan biraz ekstra işlevsellik kazandırır. Örneğin, enum üyeleri tamsayılardan farklıdır ve a name
ve a'dan oluşurlar value
.
class Animal(Enum):
DOG = 1
CAT = 2
print(Animal.DOG)
# <Animal.DOG: 1>
print(Animal.DOG.value)
# 1
print(Animal.DOG.name)
# "DOG"
Değerleri yazmak istemiyorsanız, aşağıdaki kısayolu kullanın:
class Animal(Enum):
DOG, CAT = range(2)
Enum
uygulamalar listelere dönüştürülebilir ve yinelenebilir . Üyelerinin sırası beyan düzenidir ve değerleriyle ilgisi yoktur. Örneğin:
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
object()
.
İşte bir uygulama:
class Enum(set):
def __getattr__(self, name):
if name in self:
return name
raise AttributeError
İşte kullanımı:
Animals = Enum(["DOG", "CAT", "HORSE"])
print(Animals.DOG)
__setattr__(self, name, value)
ve belki de __delattr__(self, name)
yanlışlıkla yazarsanız Animals.DOG = CAT
, sessizce başarılı olmaz.
Animals.DOG
; ayrıca, sabitlerin değerleri dizedir, böylece bu sabitlerle karşılaştırmalar, örneğin tamsayılara değer olarak izin verilenden daha yavaştır.
setattr()
içinde işlev kullanarak çalıştı . Bunun aynı şekilde çalıştığını varsayıyorum: sınıf Enum (nesne): def __init __ (self, enum_string_list): eğer type (enum_string_list) == list: enum_string için enum_string_list: setattr (self, enum_string, enum_string) başka: yükselt AttributeError__init__()
__getattr__()
try-except
blokta nasıl kontrol edersiniz ?
Sayısal değerlere ihtiyacınız varsa, en hızlı yol şudur:
dog, cat, rabbit = range(3)
Python 3.x'te ayrıca, sonunda bellek israfını önemsememeniz ve sayamayacağınız durumlarda aralığın kalan tüm değerlerini emecek olan yıldızlı bir yer tutucu ekleyebilirsiniz.
dog, cat, rabbit, horse, *_ = range(100)
Sizin için en iyi çözüm sahte neye ihtiyacınız olduğuna bağlıdır enum
.
Basit numaralandırma:
enum
Yalnızca farklı öğeleri tanımlayan bir ad listesine ihtiyacınız varsa , Mark Harrison'ın çözümü (yukarıda) harika:
Pen, Pencil, Eraser = range(0, 3)
A kullanmak, range
herhangi bir başlangıç değeri ayarlamanızı da sağlar :
Pen, Pencil, Eraser = range(9, 12)
Yukarıdakilere ek olarak, öğelerin bir çeşit konteynere ait olmasını da istiyorsanız , bunları bir sınıfa gömün:
class Stationery:
Pen, Pencil, Eraser = range(0, 3)
Numaralandırma öğesini kullanmak için artık kapsayıcı adını ve öğe adını kullanmanız gerekir:
stype = Stationery.Pen
Karmaşık numaralandırma:
Uzun enum listeleri veya enum'un daha karmaşık kullanımları için bu çözümler yeterli olmayacaktır. Python Yemek Kitabında yayınlanan Python'da Numaralandırma Simülasyonu için Will Ware tarifine bakabilirsiniz . Bunun çevrimiçi bir sürümünü burada bulabilirsiniz .
Daha fazla bilgi:
PEP 354: Python'daki numaralandırmalar, Python'daki numaralandırma teklifinin ve neden reddedildiğinin ilginç ayrıntılarına sahiptir.
range
0 ise ilk argüman atlayabilirsiniz
my_enum = dict(map(reversed, enumerate(str.split('Item0 Item1 Item2'))))
. Daha sonra my_enum
aramada kullanılabilir, örneğin my_enum['Item0']
bir diziye bir indeks olabilir. str.split
Herhangi bir kopya varsa bir istisna atan bir fonksiyonun sonucunu sarmak isteyebilirsiniz .
Flag1, Flag2, Flag3 = [2**i for i in range(3)]
Java JDK öncesi 5'de kullanılan tipafe enum paterninin birçok avantajı vardır. Alexandru'nun cevabında olduğu gibi, bir sınıf yaratırsınız ve sınıf düzeyinde alanlar enum değerleridir; ancak, enum değerleri küçük tamsayılar yerine sınıfın örnekleridir. Bunun avantajı, enum değerlerinizin yanlışlıkla küçük tamsayılarla eşit olmamasıdır, nasıl yazdırılacağını kontrol edebilir, faydalıysa keyfi yöntemler ekleyebilir ve isinstance kullanarak iddialarda bulunabilirsiniz:
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 ile ilgili yeni bir iş parçacığı , vahşi doğada birkaç enum kütüphanesi olduğunu belirtti:
Bir Enum sınıfı bir astar olabilir.
class Enum(tuple): __getattr__ = tuple.index
Nasıl kullanılır (ileri ve geri arama, anahtarlar, değerler, öğeler vb.)
>>> State = Enum(['Unclaimed', 'Claimed'])
>>> State.Claimed
1
>>> State[1]
'Claimed'
>>> State
('Unclaimed', 'Claimed')
>>> range(len(State))
[0, 1]
>>> [(k, State[k]) for k in range(len(State))]
[(0, 'Unclaimed'), (1, 'Claimed')]
>>> [(k, getattr(State, k)) for k in State]
[('Unclaimed', 0), ('Claimed', 1)]
in
, düzenli üyeleri aramak için anahtar kelimeyi kullanmama izin verin . Örnek kullanım:'Claimed' in Enum(['Unclaimed', 'Claimed'])
Ben de katılıyorum. Python'da tip güvenliğini zorunlu kılmayalım, ama kendimi aptalca hatalardan korumak istiyorum. Peki bunun hakkında ne düşünüyoruz?
class Animal(object):
values = ['Horse','Dog','Cat']
class __metaclass__(type):
def __getattr__(self, name):
return self.values.index(name)
Numaralarımı tanımlarken beni değer-çarpışmadan koruyor.
>>> Animal.Cat
2
Bir başka kullanışlı avantaj daha var: gerçekten hızlı geri aramalar:
def name_of(self, i):
return self.values[i]
Animal = Enum('horse', 'dog', 'cat')
. Ayrıca self.values eksik bir öğe durumunda getattr ValueError yakalamak - bunun yerine verilen ad dizesi ile bir AttributeError yükseltmek daha iyi görünüyor. Metaclass'ı Python 2.7'de bu alandaki sınırlı bilgiye dayanarak çalıştıramadım, ancak özel Enum sınıfım düz örnek yöntemlerle iyi çalışıyor.
Python'un yerleşik bir eşdeğeri yoktur enum
ve diğer cevapların kendi uygulamanızı uygulamak için fikirleri vardır (ayrıca Python yemek kitabındaki üst sürümle de ilgilenebilirsiniz ).
Ancak, bir enum
C için çağrılacak durumlarda , genellikle sadece basit dizeleri kullanarak sonuçlanır : nesnelerin / niteliklerin uygulanma şekli nedeniyle, (C) Python zaten kısa dizelerle çok hızlı çalışmak için optimize edilmiştir, bu yüzden olmaz tamsayıları kullanmanın herhangi bir performans avantajı olmaması. Yazım hatalarına / geçersiz değerlere karşı korunmak için seçilen yerlere kontrol ekleyebilirsiniz.
ANIMALS = ['cat', 'dog', 'python']
def take_for_a_walk(animal):
assert animal in ANIMALS
...
(Sınıf kullanmaya kıyasla bir dezavantaj, otomatik tamamlama avantajını kaybetmenizdir)
2013-05-10'da Guido 435 PEP kabul etmeyi kabul etti Python 3.4 standart kütüphanesine . Bu, Python'un numaralandırmalar için yerleşik desteğe sahip olduğu anlamına gelir!
Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 ve 2.4 için bir backport mevcut. Enum34 olarak Pypi'de .
Beyan:
>>> from enum import Enum
>>> class Color(Enum):
... red = 1
... green = 2
... blue = 3
Temsil:
>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<Color.red: 1>
Tekrar:
>>> for color in Color:
... print(color)
...
Color.red
Color.green
Color.blue
Programlı erişim:
>>> Color(1)
Color.red
>>> Color['blue']
Color.blue
Daha fazla bilgi için teklife bakın . Muhtemelen yakında resmi belgeler gelecektir.
Python enums tanımlamak gibi tercih ederim:
class Animal:
class Dog: pass
class Cat: pass
x = Animal.Dog
Tamsayıların benzersiz olduğundan emin olmak için endişelenmenize gerek olmadığından tamsayı kullanmaktan daha fazla hata geçirmezdir (örneğin, Dog = 1 ve Cat = 1 derseniz, vidalanırsınız).
Yazım hataları hakkında endişelenmenize gerek olmadığı için dizeleri kullanmaktan daha fazla hata geçirmezdir (örn. X == "catt" sessizce başarısız olur, ancak x == Animal.Catt bir çalışma zamanı istisnasıdır).
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()
Şöyle kullanın:
Animal = enum('DOG', 'CAT')
Animal.DOG # returns 0
Animal.CAT # returns 1
Animal.DOG = 2 # raises NotImplementedError
sadece benzersiz semboller istiyorsanız ve değerleri umursamıyorsanız, bu satırı değiştirin:
__metaclass__ = M_add_class_attribs(enumerate(names))
Bununla:
__metaclass__ = M_add_class_attribs((object(), name) for name in names)
enum(names)
için enum(*names)
onu ararken o zaman ekstra parantez düşebilir -.
Python 3.4'ten, numaralandırmalar için resmi destek olacak. Belgeleri ve örnekleri burada Python 3.4 belgeleri sayfasında bulabilirsiniz .
Numaralandırmalar, sözdizimi kullanılarak okunmasını ve yazılmasını kolaylaştırır. Alternatif bir oluşturma yöntemi Fonksiyonel API'de açıklanmaktadır. Bir numaralandırma tanımlamak için, Numaralandırma'yı aşağıdaki gibi alt sınıflayın:
from enum import Enum
class Color(Enum):
red = 1
green = 2
blue = 3
Hmmm ... Sanırım bir numaraya en yakın şey, sözlük olarak şöyle tanımlanacaktır:
months = {
'January': 1,
'February': 2,
...
}
veya
months = dict(
January=1,
February=2,
...
)
Ardından, bunun gibi sabitler için sembolik adı kullanabilirsiniz:
mymonth = months['January']
Tuples listesi veya tuples tuples gibi başka seçenekler de vardır, ancak söz konusu değere erişmek için "sembolik" (sabit dize) yolunu sunan tek sözlüktür.
Edit: Ben de Alexandru'nun cevabını seviyorum!
Python'da bir enumun başka, çok basit bir uygulaması namedtuple
:
from collections import namedtuple
def enum(*keys):
return namedtuple('Enum', keys)(*keys)
MyEnum = enum('FOO', 'BAR', 'BAZ')
Veya alternatif olarak,
# With sequential number values
def enum(*keys):
return namedtuple('Enum', keys)(*range(len(keys)))
# From a dict / keyword args
def enum(**kwargs):
return namedtuple('Enum', kwargs.keys())(*kwargs.values())
Yukarıdaki alt sınıflar gibi set
, bu da şunları sağlar:
'FOO' in MyEnum
other = MyEnum.FOO
assert other == MyEnum.FOO
Ancak farklı anahtarlara ve değerlere sahip olabileceğinden daha fazla esnekliğe sahiptir. Bu izin verir
MyEnum.FOO < MyEnum.BAR
sıralı sayı değerlerini dolduran sürümü kullanırsanız beklenen şekilde davranır.
Ne kullanıyorum:
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))
Nasıl kullanılır:
>>> 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'))
Böylece bu size state.PUBLISHED ve iki tuples gibi tamsayı sabitlerini Django modellerinde seçenek olarak kullanmak için verir.
davidg dicts kullanmanızı önerir. Bir adım daha ileri gidip setleri kullanırım:
months = set('January', 'February', ..., 'December')
Artık bir değerin kümedeki değerlerden biriyle eşleşip eşleşmediğini test edebilirsiniz:
if m in months:
dF gibi olsa da, genellikle sadece numaralandırma yerine dize sabitleri kullanın.
Bu gördüğüm en iyisi: "Python'da Birinci Sınıf Numaralandırmalar"
http://code.activestate.com/recipes/413486/
Size bir sınıf verir ve sınıf tüm numaralandırmaları içerir. Numaralamalar birbirleriyle karşılaştırılabilir, ancak belirli bir değeri yoktur; bunları tamsayı değeri olarak kullanamazsınız. (İlk başta buna direndim çünkü tamsayı değerler olan C numaralarına alışkınım. Ama bir tamsayı olarak kullanamazsanız, yanlışlıkla bir tamsayı olarak kullanamazsınız, bu yüzden genel olarak bir kazanım olduğunu düşünüyorum .) Her numaralandırma benzersiz bir değerdir. Numaraları yazdırabilir, üzerlerini yineleyebilir, numaralandırma değerinin numarada "olduğunu" test edebilirsiniz. Oldukça eksiksiz ve kaygan.
Düzenle (cfi): Yukarıdaki bağlantı Python 3 uyumlu değil. İşte Python 3 için enum.py portum:
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)
.__int__()
yöntem bir enum için bir istisna ortaya koymalıdır; ancak değeri elde etmenin bir yolu olmalı. Ve sınıf tanımlama zamanında belirli tamsayı değerleri ayarlamak mümkün olmalıdır, böylece stat
modüldeki sabitler gibi şeyler için bir enum kullanabilirsiniz .
İkili dosya biçimini deşifre etmek için bir Enum sınıfına ihtiyacım vardı. İstediğim özellikler özlü numaralandırma tanımı, tamsayı değeri veya dize ile enum örneklerini özgürce oluşturma yeteneği ve kullanışlı bir repr
yönlendirme. İşte sonuçta:
>>> class Enum(int):
... def __new__(cls, value):
... if isinstance(value, str):
... return getattr(cls, value)
... elif isinstance(value, int):
... return cls.__index[value]
... def __str__(self): return self.__name
... def __repr__(self): return "%s.%s" % (type(self).__name__, self.__name)
... class __metaclass__(type):
... def __new__(mcls, name, bases, attrs):
... attrs['__slots__'] = ['_Enum__name']
... cls = type.__new__(mcls, name, bases, attrs)
... cls._Enum__index = _index = {}
... for base in reversed(bases):
... if hasattr(base, '_Enum__index'):
... _index.update(base._Enum__index)
... # create all of the instances of the new class
... for attr in attrs.keys():
... value = attrs[attr]
... if isinstance(value, int):
... evalue = int.__new__(cls, value)
... evalue._Enum__name = attr
... _index[value] = evalue
... setattr(cls, attr, evalue)
... return cls
...
Tuhaf bir kullanım örneği:
>>> class Citrus(Enum):
... Lemon = 1
... Lime = 2
...
>>> Citrus.Lemon
Citrus.Lemon
>>>
>>> Citrus(1)
Citrus.Lemon
>>> Citrus(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __new__
KeyError: 5
>>> class Fruit(Citrus):
... Apple = 3
... Banana = 4
...
>>> Fruit.Apple
Fruit.Apple
>>> Fruit.Lemon
Citrus.Lemon
>>> Fruit(1)
Citrus.Lemon
>>> Fruit(3)
Fruit.Apple
>>> "%d %s %r" % ((Fruit.Apple,)*3)
'3 Apple Fruit.Apple'
>>> Fruit(1) is Citrus.Lemon
True
Ana Özellikler:
str()
, int()
verepr()
tüm üretmek en yararlı olası çıkış, enumartion sırasıyla adı, tam sayı değer, ve değerlendirir numaralandırma için geri bir Python ifadesi.is
__instancecheck__
yöntem tanımlar . Sınıflar örneklerin koleksiyonu değildir, bu yüzden 1 in Fruit
saçmadır. Ancak, bağlantılı sürüm isinstance(1, Fruit)
, sınıflar ve örnekler nosyonu açısından daha doğru olacağını destekler .
Python'daki yeni standart PEP 435'tir , bu nedenle Python'un gelecekteki sürümlerinde bir Enum sınıfı mevcut olacaktır:
>>> from enum import Enum
Ancak şimdi kullanmaya başlamak için PEP'i motive eden orijinal kütüphaneyi kurabilirsiniz :
$ pip install flufl.enum
Daha sonra çevrimiçi kılavuzuna göre kullanabilirsiniz :
>>> from flufl.enum import Enum
>>> class Colors(Enum):
... red = 1
... green = 2
... blue = 3
>>> for color in Colors: print color
Colors.red
Colors.green
Colors.blue
def enum(*sequential, **named):
enums = dict(zip(sequential, [object() for _ in range(len(sequential))]), **named)
return type('Enum', (), enums)
Adını verirseniz, sorununuz var, ancak değerler yerine nesne oluşturmuyorsanız bunu yapmanıza izin verir:
>>> DOG = enum('BARK', 'WALK', 'SIT')
>>> CAT = enum('MEOW', 'WALK', 'SIT')
>>> DOG.WALK == CAT.WALK
False
Burada yer alan diğer uygulamaları kullanırken (örneğimde adlandırılmış örnekleri kullanırken), farklı numaralandırmalardan nesneleri karşılaştırmaya çalışmamanız gerekir. İşte olası bir tuzak:
>>> DOG = enum('BARK'=1, 'WALK'=2, 'SIT'=3)
>>> CAT = enum('WALK'=1, 'SIT'=2)
>>> pet1_state = DOG.BARK
>>> pet2_state = CAT.WALK
>>> pet1_state == pet2_state
True
Olmadı!
Alec Thomas'ın çözümünü gerçekten seviyorum (http://stackoverflow.com/a/1695250):
def enum(**enums):
'''simple constant "enums"'''
return type('Enum', (object,), enums)
Zarif ve temiz görünüyor, ancak sadece belirtilen özelliklere sahip bir sınıf oluşturan bir işlev.
Fonksiyonda küçük bir değişiklikle, biraz daha 'numara' olarak hareket etmesini sağlayabiliriz:
Not: Aşağıdaki örnekleri, pygtk yeni stil 'numaralar' (Gtk.MessageType.WARNING gibi) davranışını yeniden çalışarak oluşturdu
def enum_base(t, **enums):
'''enums with a base class'''
T = type('Enum', (t,), {})
for key,val in enums.items():
setattr(T, key, T(val))
return T
Bu, belirtilen bir türe dayalı bir enum oluşturur. Önceki işlev gibi öznitelik erişimi vermenin yanı sıra, türlere göre bir Enum beklediğiniz gibi davranır. Ayrıca temel sınıfı devralır.
Örneğin, tamsayı numaralandırır:
>>> Numbers = enum_base(int, ONE=1, TWO=2, THREE=3)
>>> Numbers.ONE
1
>>> x = Numbers.TWO
>>> 10 + x
12
>>> type(Numbers)
<type 'type'>
>>> type(Numbers.ONE)
<class 'Enum'>
>>> isinstance(x, Numbers)
True
Bu yöntemle yapılabilecek bir başka ilginç şey, yerleşik yöntemleri geçersiz kılarak belirli davranışı özelleştirmektir:
def enum_repr(t, **enums):
'''enums with a base class and repr() output'''
class Enum(t):
def __repr__(self):
return '<enum {0} of type Enum({1})>'.format(self._name, t.__name__)
for key,val in enums.items():
i = Enum(val)
i._name = key
setattr(Enum, key, i)
return Enum
>>> Numbers = enum_repr(int, ONE=1, TWO=2, THREE=3)
>>> repr(Numbers.ONE)
'<enum ONE of type Enum(int)>'
>>> str(Numbers.ONE)
'1'
PyPI'nin numaralandırma paketi, enumların sağlam bir şekilde uygulanmasını sağlar. Daha önceki bir cevap PEP 354'ten bahsetmiştir; bu reddedildi ancak teklif http://pypi.python.org/pypi/enum uygulandı .
Kullanımı kolay ve zariftir:
>>> 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'
Alexandru'nun numaralandırmalar için sınıf sabitlerini kullanma önerisi gayet iyi çalışıyor.
Ayrıca insan tarafından okunabilir bir dize temsili aramak için her sabit kümesi için bir sözlük eklemek istiyorum.
Bu iki amaca hizmet eder: a) numaralandırmayı güzel yazdırmak için basit bir yol sağlar ve b) sözlük, sabitleri mantıksal olarak gruplandırır, böylece üyeliğinizi test edebilirsiniz.
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())
İşte değerli bulduğum bazı farklı özelliklere sahip bir yaklaşım:
ve en önemlisi farklı türdeki numaralandırmalar arasındaki karşılaştırmaları önler !
Http://code.activestate.com/recipes/413486-first-class-enums-in-python'a çok yakın .
Bu yaklaşımda neyin farklı olduğunu göstermek için birçok doktora dahil edildi.
def enum(*names):
"""
SYNOPSIS
Well-behaved enumerated type, easier than creating custom classes
DESCRIPTION
Create a custom type that implements an enumeration. Similar in concept
to a C enum but with some additional capabilities and protections. See
http://code.activestate.com/recipes/413486-first-class-enums-in-python/.
PARAMETERS
names Ordered list of names. The order in which names are given
will be the sort order in the enum type. Duplicate names
are not allowed. Unicode names are mapped to ASCII.
RETURNS
Object of type enum, with the input names and the enumerated values.
EXAMPLES
>>> letters = enum('a','e','i','o','u','b','c','y','z')
>>> letters.a < letters.e
True
## index by property
>>> letters.a
a
## index by position
>>> letters[0]
a
## index by name, helpful for bridging string inputs to enum
>>> letters['a']
a
## sorting by order in the enum() create, not character value
>>> letters.u < letters.b
True
## normal slicing operations available
>>> letters[-1]
z
## error since there are not 100 items in enum
>>> letters[99]
Traceback (most recent call last):
...
IndexError: tuple index out of range
## error since name does not exist in enum
>>> letters['ggg']
Traceback (most recent call last):
...
ValueError: tuple.index(x): x not in tuple
## enums must be named using valid Python identifiers
>>> numbers = enum(1,2,3,4)
Traceback (most recent call last):
...
AssertionError: Enum values must be string or unicode
>>> a = enum('-a','-b')
Traceback (most recent call last):
...
TypeError: Error when calling the metaclass bases
__slots__ must be identifiers
## create another enum
>>> tags = enum('a','b','c')
>>> tags.a
a
>>> letters.a
a
## can't compare values from different enums
>>> letters.a == tags.a
Traceback (most recent call last):
...
AssertionError: Only values from the same enum are comparable
>>> letters.a < tags.a
Traceback (most recent call last):
...
AssertionError: Only values from the same enum are comparable
## can't update enum after create
>>> letters.a = 'x'
Traceback (most recent call last):
...
AttributeError: 'EnumClass' object attribute 'a' is read-only
## can't update enum after create
>>> del letters.u
Traceback (most recent call last):
...
AttributeError: 'EnumClass' object attribute 'u' is read-only
## can't have non-unique enum values
>>> x = enum('a','b','c','a')
Traceback (most recent call last):
...
AssertionError: Enums must not repeat values
## can't have zero enum values
>>> x = enum()
Traceback (most recent call last):
...
AssertionError: Empty enums are not supported
## can't have enum values that look like special function names
## since these could collide and lead to non-obvious errors
>>> x = enum('a','b','c','__cmp__')
Traceback (most recent call last):
...
AssertionError: Enum values beginning with __ are not supported
LIMITATIONS
Enum values of unicode type are not preserved, mapped to ASCII instead.
"""
## must have at least one enum value
assert names, 'Empty enums are not supported'
## enum values must be strings
assert len([i for i in names if not isinstance(i, types.StringTypes) and not \
isinstance(i, unicode)]) == 0, 'Enum values must be string or unicode'
## enum values must not collide with special function names
assert len([i for i in names if i.startswith("__")]) == 0,\
'Enum values beginning with __ are not supported'
## each enum value must be unique from all others
assert names == uniquify(names), 'Enums must not repeat values'
class EnumClass(object):
""" See parent function for explanation """
__slots__ = names
def __iter__(self):
return iter(constants)
def __len__(self):
return len(constants)
def __getitem__(self, i):
## this makes xx['name'] possible
if isinstance(i, types.StringTypes):
i = names.index(i)
## handles the more normal xx[0]
return constants[i]
def __repr__(self):
return 'enum' + str(names)
def __str__(self):
return 'enum ' + str(constants)
def index(self, i):
return names.index(i)
class EnumValue(object):
""" See parent function for explanation """
__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):
assert self.enumtype is other.enumtype, 'Only values from the same enum are comparable'
return cmp(self.value, other.value)
def __invert__(self):
return constants[maximum - self.value]
def __nonzero__(self):
## return bool(self.value)
## Original code led to bool(x[0])==False, not correct
return True
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
Alec Thomas'ın çözümünün bir çeşidi :
def enum(*args, **kwargs):
return type('Enum', (), dict((y, x) for x, y in enumerate(args), **kwargs))
x = enum('POOH', 'TIGGER', 'EEYORE', 'ROO', 'PIGLET', 'RABBIT', 'OWL')
assert x.POOH == 0
assert x.TIGGER == 1
Bu çözüm, bir liste olarak tanımlanan numaralandırma için bir sınıf almanın basit bir yoludur (artık can sıkıcı tamsayı atamaları yok):
enumeration.py:
import new
def create(class_name, names):
return new.classobj(
class_name, (object,), dict((y, x) for x, y in enumerate(names))
)
example.py:
import enumeration
Colors = enumeration.create('Colors', (
'red',
'orange',
'yellow',
'green',
'blue',
'violet',
))
type(class_name, (object,), dict(...))
?
Orijinal numaralandırma önerisi PEP 354 , yıllar önce reddedilirken, geri dönmeye devam ediyor. 3.2'ye bir tür enum eklenmesi amaçlandı, ancak 3.3'e geri itildi ve unutuldu. Ve şimdi Python 3.4'e dahil edilmek üzere tasarlanmış bir PEP 435 var . PEP 435'in referans uygulamasıdır flufl.enum
.
Nisan 2013 itibarı ile , 3.4'te standart kütüphaneye bir şeylerin eklenmesi gerektiği konusunda genel bir fikir birliği var gibi görünüyor - insanlar "bu" şeyin ne olması gerektiği konusunda anlaşabildikleri sürece. Zor kısmı bu. Burada ve burada başlayan konuları ve 2013'ün ilk aylarında yarım düzine diğer konuları görün.
Bu arada, bu her ortaya çıktığında, PyPI, ActiveState, vb.'de bir dizi yeni tasarım ve uygulama görünür, bu nedenle FLUFL tasarımını beğenmezseniz, bir PyPI araması yapmayı deneyin .
Aşağıdakileri kullanın.
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']
Bunu Django model seçimleri için kullandım ve çok pitonik görünüyor. Gerçekten bir Enum değil, ama işi yapıyor.