Bagaimana cara mengubah int ke enum dengan python?

96

Menggunakan fitur Enum baru (via backport enum34 ) dengan python 2.7.6.

Diberikan definisi berikut, bagaimana cara mengonversi int ke nilai Enum yang sesuai?

from enum import Enum

class Fruit(Enum):
    Apple = 4
    Orange = 5
    Pear = 6

Saya tahu saya dapat membuat serangkaian pernyataan if untuk melakukan konversi tetapi apakah ada cara pythonic yang mudah untuk mengonversi? Pada dasarnya, saya ingin fungsi ConvertIntToFruit (int) yang mengembalikan nilai enum.

Kasus penggunaan saya adalah saya memiliki file csv rekaman tempat saya membaca setiap rekaman menjadi suatu objek. Salah satu bidang file adalah bidang integer yang mewakili pencacahan. Saat saya mengisi objek, saya ingin mengubah bidang integer dari file menjadi nilai Enum yang sesuai di objek.

Pengguna
sumber

Jawaban:

165

Anda 'memanggil' Enumkelas:

Fruit(5)

berubah 5menjadi Fruit.Orange:

>>> from enum import Enum
>>> class Fruit(Enum):
...     Apple = 4
...     Orange = 5
...     Pear = 6
... 
>>> Fruit(5)
<Fruit.Orange: 5>

Dari bagian Akses terprogram ke anggota enumerasi dan atribut mereka di dokumentasi:

Kadang-kadang berguna untuk mengakses anggota dalam pencacahan secara terprogram (yaitu situasi di mana Color.redtidak dapat dilakukan karena warna persisnya tidak diketahui pada waktu penulisan program). Enummengizinkan akses tersebut:

>>> Color(1)
<Color.red: 1>
>>> Color(3)
<Color.blue: 3>

Dalam catatan terkait: untuk memetakan nilai string yang berisi nama anggota enum, gunakan subscription:

>>> s = 'Apple'
>>> Fruit[s]
<Fruit.Apple: 4>
Martijn Pieters
sumber
Terima kasih baru saja mendapatkannya saat saya membaca ulang dokumentasi. Tidak jelas bagi saya pada skim pertama saya. Juga saya hanya mencoba menggunakan string dan senang melihat itu berfungsi ketika nilai pencacahan adalah string juga dan saya mengasumsikan nilai objek sewenang-wenang.
Pengguna
Sangat bagus, jadi konversi berdasarkan nilai. Apakah ada analogi dengan nama selain melalui pemahaman daftar untuk menyaring melalui daftar enum dan mencocokkan atribut nama?
jxramos
4
@jxramos ikuti tautan dokumentasi dalam jawaban saya, secara eksplisit tercakup di sana. Gunakan akses barang: Fruit['Orange'].
Martijn Pieters
Bingo, sangat luar biasa! Aku mencari halaman untuk convert, coercedan casttapi tidak memukul apa-apa. Sepertinya keajaiban itu access enum members by name, use item access. Perfecto, terima kasih banyak, akan membersihkan kode saya dengan sintaks ini.
jxramos
Yang lebih keren adalah saya dapat menggunakan hal-hal seperti "foobar" in Fruit.__members__untuk menguji keanggotaan dan bahkan melakukan Fruit.get( 'foobar', Fruit.Orange )untuk mendapatkan rasa Enum default itu. Kode saya terlihat jauh lebih sederhana dengan menghapus semua perancah pencarian aksesori yang saya buat sebelumnya.
jxramos
1

Saya pikir itu dalam kata-kata sederhana adalah untuk mengkonversi intnilai ke Enumdengan menelepon EnumType(int_value), setelah akses bahwa namedari Enumobjek:

my_fruit_from_int = Fruit(5) #convert to int
fruit_name = my_fruit_from_int.name #get the name
print(fruit_name) #Orange will be printed here

Atau sebagai fungsi:

def convert_int_to_fruit(int_value):
    try:
        my_fruit_from_int = Fruit(int_value)
        return my_fruit_from_int.name
    except:
        return None
Ali Ezzat Odeh
sumber
-1

Saya menginginkan sesuatu yang serupa sehingga saya dapat mengakses salah satu bagian dari pasangan nilai dari satu referensi. Versi vanilla:

#!/usr/bin/env python3


from enum import IntEnum


class EnumDemo(IntEnum):
    ENUM_ZERO       = 0
    ENUM_ONE        = 1
    ENUM_TWO        = 2
    ENUM_THREE      = 3
    ENUM_INVALID    = 4


#endclass.


print('Passes')
print('1) %d'%(EnumDemo['ENUM_TWO']))
print('2) %s'%(EnumDemo['ENUM_TWO']))
print('3) %s'%(EnumDemo.ENUM_TWO.name))
print('4) %d'%(EnumDemo.ENUM_TWO))
print()


print('Fails')
print('1) %d'%(EnumDemo.ENUM_TWOa))

Kegagalan memunculkan pengecualian seperti yang diharapkan.

Versi yang lebih kuat:

#!/usr/bin/env python3


class EnumDemo():


    enumeration =   (
                        'ENUM_ZERO',    # 0.
                        'ENUM_ONE',     # 1.
                        'ENUM_TWO',     # 2.
                        'ENUM_THREE',   # 3.
                        'ENUM_INVALID'  # 4.
                    )


    def name(self, val):
        try:

            name = self.enumeration[val]
        except IndexError:

            # Always return last tuple.
            name = self.enumeration[len(self.enumeration) - 1]

        return name


    def number(self, val):
        try:

            index = self.enumeration.index(val)
        except (TypeError, ValueError):

            # Always return last tuple.
            index = (len(self.enumeration) - 1)

        return index


#endclass.


print('Passes')
print('1) %d'%(EnumDemo().number('ENUM_TWO')))
print('2) %s'%(EnumDemo().number('ENUM_TWO')))
print('3) %s'%(EnumDemo().name(1)))
print('4) %s'%(EnumDemo().enumeration[1]))
print()
print('Fails')
print('1) %d'%(EnumDemo().number('ENUM_THREEa')))
print('2) %s'%(EnumDemo().number('ENUM_THREEa')))
print('3) %s'%(EnumDemo().name(11)))
print('4) %s'%(EnumDemo().enumeration[-1]))

Jika tidak digunakan dengan benar, ini menghindari pembuatan pengecualian dan, sebagai gantinya, mengembalikan indikasi kesalahan. Cara yang lebih Pythonic untuk melakukan ini adalah dengan mengirimkan kembali "Tidak ada" tetapi aplikasi khusus saya menggunakan teks secara langsung.

pengguna3355323
sumber
Mengapa tidak mendefinisikan __int__dan __str__metode pada instance Enum saja?
Tim