Saya terutama adalah pengembang C #, tetapi saat ini saya sedang mengerjakan proyek dengan Python.
Bagaimana saya bisa mewakili yang setara dengan Enum dengan Python?
sumber
Saya terutama adalah pengembang C #, tetapi saat ini saya sedang mengerjakan proyek dengan Python.
Bagaimana saya bisa mewakili yang setara dengan Enum dengan Python?
Enum telah ditambahkan ke Python 3.4 seperti yang dijelaskan dalam PEP 435 . Ini juga telah di- backport ke 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, dan 2.4 di pypi.
Untuk teknik Enum yang lebih lanjut, coba perpustakaan aenum (2.7, 3.3+, penulis yang sama dengan enum34
. Code tidak sepenuhnya kompatibel antara py2 dan py3, mis. Anda akan membutuhkan __order__
python 2 ).
enum34
, lakukan$ pip install enum34
aenum
, lakukan$ pip install aenum
Menginstal enum
(tidak ada angka) akan menginstal versi yang sama sekali berbeda dan tidak kompatibel.
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)
atau yang setara:
class Animal(Enum):
ant = 1
bee = 2
cat = 3
dog = 4
Dalam versi sebelumnya, satu cara untuk mencapai enum adalah:
def enum(**enums):
return type('Enum', (), enums)
yang digunakan seperti ini:
>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'
Anda juga dapat dengan mudah mendukung pencacahan otomatis dengan sesuatu seperti ini:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
return type('Enum', (), enums)
dan digunakan seperti ini:
>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1
Dukungan untuk mengonversi nilai kembali ke nama dapat ditambahkan dengan cara ini:
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)
Ini menimpa apa pun dengan nama itu, tetapi ini berguna untuk menampilkan enum Anda menjadi keluaran. Ini akan melempar KeyError jika pemetaan terbalik tidak ada. Dengan contoh pertama:
>>> Numbers.reverse_mapping['three']
'THREE'
**named
) dalam fungsi enum untuk versi yang lebih lama adalah untuk mendukung nilai-nilai khusus:enum("blue", "red", "green", black=0)
Sebelum PEP 435, Python tidak memiliki padanan tapi Anda bisa menerapkannya sendiri.
Saya sendiri, saya suka menjaganya tetap sederhana (saya telah melihat beberapa contoh rumit yang mengerikan di internet), sesuatu seperti ini ...
Di Python 3.4 ( PEP 435 ), Anda bisa membuat Enum kelas dasar. Ini memberi Anda sedikit fungsi tambahan, dijelaskan dalam PEP. Sebagai contoh, anggota enum berbeda dari bilangan bulat, dan mereka terdiri dari a
name
dan avalue
.Jika Anda tidak ingin mengetik nilai, gunakan pintasan berikut:
Enum
implementasi dapat dikonversi menjadi daftar dan dapat diubah . Urutan anggotanya adalah perintah deklarasi dan tidak ada hubungannya dengan nilai-nilai mereka. Sebagai contoh:sumber
object()
.Berikut ini satu implementasinya:
Berikut ini adalah penggunaannya:
sumber
__setattr__(self, name, value)
dan mungkin__delattr__(self, name)
sehingga jika Anda secara tidak sengaja menulisAnimals.DOG = CAT
, itu tidak akan berhasil secara diam-diam.Animals.DOG
; juga, nilai-nilai konstanta adalah string, sehingga perbandingan dengan konstanta ini lebih lambat daripada jika, katakanlah, bilangan bulat diizinkan sebagai nilai.setattr()
fungsi di dalam__init__()
metode alih-alih__getattr__()
metode overidding . Saya berasumsi ini seharusnya bekerja dengan cara yang sama: class Enum (objek): def __init __ (self, enum_string_list): if type (enum_string_list) == list: for enum_string in enum_string_list: setattr (self, enum_string, enum_string) lain: meningkatkan AttributeErrortry-except
blok?Jika Anda membutuhkan nilai numerik, inilah cara tercepat:
Di Python 3.x Anda juga bisa menambahkan placeholder yang berkilau bintangnya di akhir, yang akan menyerap semua nilai yang tersisa dari rentang jika Anda tidak keberatan membuang-buang memori dan tidak dapat menghitung:
sumber
Solusi terbaik untuk Anda akan tergantung pada apa yang Anda butuhkan dari kepalsuan Anda
enum
.Enum sederhana:
Jika Anda
enum
hanya memerlukan daftar nama yang mengidentifikasi item yang berbeda , solusinya oleh Mark Harrison (di atas) sangat bagus:Menggunakan
range
juga memungkinkan Anda untuk menetapkan nilai awal :Selain hal-hal di atas, jika Anda juga mensyaratkan bahwa barang-barang itu milik wadah semacam, maka sematkan di kelas:
Untuk menggunakan item enum, Anda sekarang harus menggunakan nama kontainer dan nama item:
Enum kompleks:
Untuk daftar panjang enum atau penggunaan enum yang lebih rumit, solusi ini tidak akan cukup. Anda bisa melihat resep oleh Will Ware untuk Mensimulasikan Enumerasi dengan Python yang diterbitkan dalam Python Cookbook . Versi online yang tersedia di sini .
Info lebih lanjut:
PEP 354: Pencacahan dengan Python memiliki detail menarik dari proposal enum dengan Python dan mengapa ditolak.
sumber
range
Anda dapat menghilangkan argumen pertama jika 0my_enum = dict(map(reversed, enumerate(str.split('Item0 Item1 Item2'))))
. Kemudianmy_enum
dapat digunakan dalam pencarian, misalnya,my_enum['Item0']
dapat menjadi indeks menjadi suatu urutan. Anda mungkin ingin membungkus hasilstr.split
dalam fungsi yang melempar pengecualian jika ada duplikat.Flag1, Flag2, Flag3 = [2**i for i in range(3)]
Pola typesafe enum yang digunakan di Java pra-JDK 5 memiliki sejumlah keunggulan. Sama seperti dalam jawaban Alexandru, Anda membuat kelas dan bidang level kelas adalah nilai enum; Namun, nilai enum adalah instance dari kelas daripada bilangan bulat kecil. Ini memiliki keuntungan bahwa nilai enum Anda tidak secara tidak sengaja membandingkan sama dengan bilangan bulat kecil, Anda dapat mengontrol bagaimana mereka dicetak, menambahkan metode arbitrer jika itu berguna dan membuat pernyataan menggunakan isinstance:
Sebuah utas terbaru tentang python-dev menunjukkan ada beberapa perpustakaan enum di alam liar, termasuk:
sumber
Kelas Enum dapat berupa one-liner.
Cara menggunakannya (memajukan dan membalikkan pencarian, kunci, nilai, item, dll.)
sumber
in
kata kunci untuk mencari anggota yang rapi. Contoh penggunaan:'Claimed' in Enum(['Unclaimed', 'Claimed'])
Jadi saya setuju. Mari kita tidak menegakkan keamanan jenis dengan Python, tapi saya ingin melindungi diri saya dari kesalahan konyol. Jadi apa yang kita pikirkan tentang ini?
Itu menjaga saya dari tabrakan nilai dalam mendefinisikan enum saya.
Ada keuntungan lain yang berguna: pencarian terbalik sangat cepat:
sumber
Animal = Enum('horse', 'dog', 'cat')
. Saya juga menangkap ValueError di getattr jika ada item yang hilang di self.values - sepertinya lebih baik untuk meningkatkan AttributeError dengan string nama yang disediakan. Saya tidak bisa membuat metaclass bekerja di Python 2.7 berdasarkan pengetahuan saya yang terbatas di area itu, tetapi kelas kustom Enum saya berfungsi dengan baik dengan metode instan.Python tidak memiliki built-in yang setara dengan
enum
, dan jawaban lain memiliki ide untuk mengimplementasikannya sendiri (Anda mungkin juga tertarik dengan versi over the top di buku masak Python).Namun, dalam situasi di mana sebuah
enum
akan dipanggil dalam C, saya biasanya berakhir hanya menggunakan string sederhana : karena cara objek / atribut diimplementasikan, (C) Python dioptimalkan untuk bekerja sangat cepat dengan string pendek, jadi tidak akan benar-benar bermanfaat untuk menggunakan bilangan bulat. Untuk menjaga dari kesalahan ketik / nilai tidak valid Anda dapat memasukkan cek di tempat-tempat yang dipilih.(Satu kelemahan dibandingkan menggunakan kelas adalah Anda kehilangan manfaat autocomplete)
sumber
Pada 2013-05-10, Guido setuju untuk menerima PEP 435 ke dalam pustaka standar Python 3.4. Ini berarti bahwa Python akhirnya telah membangun dukungan untuk enumerasi!
Ada backport yang tersedia untuk Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, dan 2.4. Ada di Pypi sebagai enum34 .
Pernyataan:
Perwakilan:
Pengulangan:
Akses terprogram:
Untuk informasi lebih lanjut, lihat proposal . Dokumentasi resmi mungkin akan segera menyusul.
sumber
Saya lebih suka mendefinisikan enum dengan Python seperti ini:
Ini lebih tahan bug daripada menggunakan bilangan bulat karena Anda tidak perlu khawatir tentang memastikan bilangan bulat itu unik (mis. Jika Anda mengatakan Dog = 1 dan Cat = 1 Anda akan mengacaukannya).
Ini lebih tahan bug daripada menggunakan string karena Anda tidak perlu khawatir tentang kesalahan ketik (mis. X == "catt" gagal diam-diam, tetapi x == Animal.Catt adalah pengecualian runtime).
sumber
Gunakan seperti ini:
jika Anda hanya ingin simbol yang unik dan tidak peduli dengan nilainya, ganti baris ini:
dengan ini:
sumber
enum(names)
keenum(*names)
- maka Anda bisa drop kurung tambahan ketika menyebutnya.Dari Python 3.4 akan ada dukungan resmi untuk enum. Anda dapat menemukan dokumentasi dan contoh di sini di halaman dokumentasi Python 3.4 .
sumber
Hmmm ... Saya kira hal yang paling dekat dengan enum adalah kamus, didefinisikan seperti ini:
atau
Kemudian, Anda dapat menggunakan nama simbolis untuk konstanta seperti ini:
Ada opsi lain, seperti daftar tupel, atau tupel tupel, tetapi kamus adalah satu-satunya yang memberi Anda cara "simbolik" (string konstan) untuk mengakses nilai.
Sunting: Saya juga menyukai jawaban Alexandru!
sumber
Lain, sangat sederhana, implementasi enum dengan Python, menggunakan
namedtuple
:atau, sebagai alternatif,
Seperti metode di atas subclass itu
set
, ini memungkinkan:Tetapi memiliki lebih banyak fleksibilitas karena dapat memiliki kunci dan nilai yang berbeda. Ini memungkinkan
untuk bertindak seperti yang diharapkan jika Anda menggunakan versi yang mengisi nilai angka berurutan.
sumber
Apa yang saya gunakan:
Cara Penggunaan:
Jadi ini memberi Anda konstanta integer seperti state.PUBLISHED dan dua-tupel untuk digunakan sebagai pilihan dalam model Django.
sumber
davidg merekomendasikan menggunakan dikt. Saya akan melangkah lebih jauh dan menggunakan set:
Sekarang Anda dapat menguji apakah suatu nilai cocok dengan salah satu nilai dalam set seperti ini:
seperti dF, meskipun, saya biasanya hanya menggunakan konstanta string di tempat enum.
sumber
Sederhana saja:
Kemudian:
sumber
Ini yang terbaik yang pernah saya lihat: "Enum Kelas Satu dengan Python"
http://code.activestate.com/recipes/413486/
Ini memberi Anda kelas, dan kelas berisi semua enum. Enum dapat dibandingkan satu sama lain, tetapi tidak memiliki nilai tertentu; Anda tidak dapat menggunakannya sebagai nilai integer. (Saya menolak ini pada awalnya karena saya terbiasa dengan C enum, yang merupakan nilai integer. Tetapi jika Anda tidak dapat menggunakannya sebagai integer, Anda tidak dapat menggunakannya sebagai integer karena kesalahan sehingga secara keseluruhan saya pikir ini adalah kemenangan .) Setiap enum adalah nilai unik. Anda dapat mencetak enum, Anda dapat mengulanginya, Anda dapat menguji bahwa nilai enum "di" enum. Cukup lengkap dan apik.
Sunting (cfi): Tautan di atas tidak kompatibel dengan Python 3. Ini port enum.py saya ke Python 3:
sumber
.__int__()
metode harus memunculkan pengecualian untuk enum; tetapi harus ada cara untuk mendapatkan nilai. Dan harus dimungkinkan untuk menetapkan nilai integer spesifik pada waktu definisi kelas, sehingga Anda dapat menggunakan enum untuk hal-hal seperti konstanta dalamstat
modul.Saya memiliki kesempatan untuk membutuhkan kelas Enum, untuk tujuan decoding format file biner. Fitur yang kebetulan saya inginkan adalah definisi enum ringkas, kemampuan untuk secara bebas membuat instance enum dengan nilai integer atau string, dan
repr
esensiasi yang bermanfaat . Inilah yang akhirnya saya dapatkan:Contoh aneh menggunakannya:
Fitur utama:
str()
,int()
danrepr()
semua menghasilkan keluaran paling berguna yang mungkin, masing-masing nama enumartion, nilai integernya, dan ekspresi Python yang mengevaluasi kembali ke enumerasi.is
sumber
__instancecheck__
metode. Kelas bukan kumpulan instance, jadi1 in Fruit
tidak masuk akal. Namun, versi tertaut mendukungisinstance(1, Fruit)
yang akan lebih benar dalam hal pengertian kelas dan instance.Standar baru dalam Python adalah PEP 435 , sehingga kelas Enum akan tersedia dalam versi Python mendatang:
Namun untuk mulai menggunakannya sekarang, Anda dapat menginstal perpustakaan asli yang memotivasi PEP:
Kemudian Anda dapat menggunakannya sesuai panduan online-nya :
sumber
Jika Anda beri nama, itu masalah Anda, tetapi jika tidak membuat objek, bukan nilai, Anda dapat melakukan ini:
Saat menggunakan implementasi lain yang diletakkan di sini (juga saat menggunakan contoh bernama dalam contoh saya), Anda harus yakin Anda tidak pernah mencoba membandingkan objek dari enum yang berbeda. Untuk inilah kemungkinan perangkap:
Astaga!
sumber
Saya sangat menyukai solusi Alec Thomas (http://stackoverflow.com/a/1695250):
Ini terlihat elegan dan bersih, tetapi hanya fungsi yang menciptakan kelas dengan atribut yang ditentukan.
Dengan sedikit modifikasi pada fungsi, kita bisa membuatnya bertindak sedikit lebih 'enumy':
Ini menciptakan enum berdasarkan jenis tertentu. Selain memberikan akses atribut seperti fungsi sebelumnya, ia berperilaku seperti yang Anda harapkan dari Enum sehubungan dengan tipe. Itu juga mewarisi kelas dasar.
Misalnya, integer enums:
Hal menarik lain yang dapat dilakukan dengan metode ini adalah menyesuaikan perilaku spesifik dengan mengganti metode bawaan:
sumber
Paket enum dari PyPI menyediakan implementasi enum yang kuat. Jawaban sebelumnya menyebutkan PEP 354; ini ditolak tetapi proposal itu diterapkan http://pypi.python.org/pypi/enum .
Penggunaannya mudah dan elegan:
sumber
Saran Alexandru untuk menggunakan konstanta kelas untuk enum bekerja dengan sangat baik.
Saya juga ingin menambahkan kamus untuk setiap rangkaian konstanta untuk mencari representasi string yang dapat dibaca manusia.
Ini melayani dua tujuan: a) menyediakan cara sederhana untuk mencetak enum Anda dengan cantik dan b) kamus secara logis mengelompokkan konstanta sehingga Anda dapat menguji keanggotaan.
sumber
Inilah pendekatan dengan beberapa karakteristik berbeda yang menurut saya berharga:
dan yang paling penting mencegah perbandingan antara enum dari berbagai jenis !
Berdasarkan erat pada http://code.activestate.com/recipes/413486-first-class-enums-in-python .
Banyak dokumen yang disertakan di sini untuk menggambarkan apa yang berbeda dari pendekatan ini.
sumber
Berikut ini varian dari solusi Alec Thomas :
sumber
Solusi ini adalah cara sederhana untuk mendapatkan kelas untuk enumerasi yang didefinisikan sebagai daftar (tidak ada lagi tugas bilangan bulat yang mengganggu):
enumeration.py:
contoh.py:
sumber
type(class_name, (object,), dict(...))
saja saja?Sementara proposal enum asli, PEP 354 , ditolak tahun lalu, itu terus muncul kembali. Beberapa jenis enum dimaksudkan untuk ditambahkan ke 3.2, tapi itu didorong kembali ke 3.3 dan kemudian dilupakan. Dan sekarang ada PEP 435 yang dimaksudkan untuk dimasukkan dalam Python 3.4. Referensi implementasi PEP 435 adalah
flufl.enum
.Pada April 2013, tampaknya ada konsensus umum bahwa sesuatu harus ditambahkan ke perpustakaan standar di 3.4 — selama orang-orang dapat sepakat tentang apa "seharusnya" itu. Itu bagian yang sulit. Lihat utas mulai di sini dan di sini , dan setengah lusin utas lainnya di awal 2013.
Sementara itu, setiap kali ini muncul, banyak desain dan implementasi baru muncul di PyPI, ActiveState, dll., Jadi jika Anda tidak menyukai desain FLUFL, coba pencarian PyPI .
sumber
Gunakan yang berikut ini.
Saya menggunakan itu untuk pilihan model Django , dan itu terlihat sangat pythonic. Ini sebenarnya bukan Enum, tetapi ia berhasil.
sumber