Apakah ada cara yang lebih baik untuk menulis pernyataan bersarang jika dalam python? [Tutup]


34

Apakah ada cara yang lebih pythonic untuk melakukan pernyataan bersarang jika selain dari ini:

def convert_what(numeral_sys_1, numeral_sys_2):

    if numeral_sys_1 == numeral_sys_2:      
        return 0
    elif numeral_sys_1 == "Hexadecimal":
        if numeral_sys_2 == "Decimal":
            return 1
        elif numeral_sys_2 == "Binary":
            return 2
    elif numeral_sys_1 == "Decimal":
        if numeral_sys_2 == "Hexadecimal":
            return 4
        elif numeral_sys_2 == "Binary":
            return 6
    elif numeral_sys_1 == "Binary":
        if numeral_sys_2 == "Hexadecimal":
            return 5
        elif numeral_sys_2 == "Decimal":
            return 3
    else:
        return 0

Skrip ini adalah bagian dari konverter sederhana.


Tanpa menggunakan struktur data lain, Anda bisa memindahkan pernyataan if-else bersarang ke dalam andkondisi untuk pernyataan if-else tingkat atas. Setidaknya akan lebih mudah dibaca seperti itu. Sayangnya, python tidak memiliki pernyataan switch.
adamkgray

Ini adalah cara pythonic. Python sengaja tidak mendukung pernyataan switch. Lihat python.org/dev/peps/pep-3103
Jongmin Baek

1
Bukan pertanyaan sama sekali, tetapi jika Anda mencoba membuat sesuatu lebih Pythonic, bagaimana dengan mendefinisikan konstanta atau enum untuk nilai kembali - lebih bagus untuk pembaca daripada "angka ajaib" ....
Mats Wichmann

Jawaban:


13

Sementara jawaban @Aryerez dan @ SencerH. bekerja, setiap nilai yang mungkin numeral_sys_1harus ditulis berulang kali untuk setiap nilai yang mungkin terjadi numeral_sys_2ketika mendaftarkan pasangan nilai, membuat struktur data lebih sulit untuk dipertahankan ketika jumlah nilai yang mungkin meningkat. Sebagai gantinya, Anda dapat menggunakan dict bersarang sebagai ganti pernyataan bersarang jika:

mapping = {
    'Hexadecimal': {'Decimal': 1, 'Binary': 2},
    'Binary': {'Decimal': 3, 'Hexadecimal': 5},
    'Decimal': {'Hexadecimal': 4, 'Binary': 6}
}
def convert_what(numeral_sys_1, numeral_sys_2):
    return mapping.get(numeral_sys_1, {}).get(numeral_sys_2, 0)

Sebagai alternatif, Anda dapat menghasilkan pasangan nilai untuk pemetaan dengan itertools.permutationsmetode, yang urutannya mengikuti urutan input:

mapping = dict(zip(permutations(('Hexadecimal', 'Decimal', 'Binary'), r=2), (1, 2, 4, 6, 3, 5)))
def convert_what(numeral_sys_1, numeral_sys_2):
    return mapping.get((numeral_sys_1, numeral_sys_2), 0)

29

Masukkan semua kombinasi yang valid untuk dictionarydari tuples, dan jika kombinasi tersebut tidak ada, kembali 0:

def convert_what(numeral_sys_1, numeral_sys_2):
    numeral_dict = {
        ("Hexadecimal", "Decimal"    ) : 1,
        ("Hexadecimal", "Binary"     ) : 2,
        ("Decimal",     "Hexadecimal") : 4, 
        ("Decimal",     "Binary"     ) : 6,
        ("Binary",      "Hexadecimal") : 5,
        ("Binary",      "Decimal"    ) : 3
    }
    return numeral_dict.get((numeral_sys_1, numeral_sys_2), 0)

Jika Anda berencana untuk menggunakan fungsi dalam satu lingkaran, mungkin merupakan ide yang lebih baik untuk mendefinisikan kamus di luar fungsi, jadi itu tidak akan dibuat kembali pada setiap panggilan ke fungsi.


2
except KeyError:
RomanPerekhrest

@ RomanPerekhrest saya telah menambahkannya, meskipun dalam pertanyaan khusus ini, fungsi itu sendiri tidak memiliki jenis kesalahan lain untuk menghasilkan yang akan memberikan output yang berbeda dari fungsi aslinya.
Aryerez

1
Paren di dalam [] berlebihan. Kecuali untuk tuple kosong, itu adalah koma yang membuatnya tuple, bukan tanda kurung, itu hanya untuk urutan operasi dalam beberapa kasus.
Gilch

4
Anda bisa menggunakan .get()metode dict dengan 0default alih-alih trypernyataan.
Gilch

@ gilch aku menjatuhkan tanda kurung. Tapi saya suka try:... except:...strukturnya.
Aryerez

17

Jika Anda yakin tidak ada nilai lain yang dapat diatur ke variabel numeral_sys_1 dan numeral_sys_2 ini adalah solusi paling sederhana dan paling bersih.

Di sisi lain, Anda harus memperluas kamus dengan kombinasinya dengan nilai yang tersedia, jika Anda memiliki nilai selain "Heksadesimal", "Desimal" dan "Biner"

Logikanya di sini adalah; jika tupel variabel dalam kunci kamus tidak sama dengan tupel variabel yang diberikan, metode .get () mengembalikan "0". Jika diberi tuple variabel cocok dengan sembarang tombol dalam kamus maka kembalikan nilai kunci yang cocok.

def convert_what(numeral_sys_1, numeral_sys_2):
    return {
        ("Hexadecimal", "Decimal") : 1, 
        ("Hexadecimal", "Binary") : 2, 
        ("Binary", "Decimal") : 3,
        ("Decimal", "Hexadecimal") : 4,
        ("Binary", "Hexadecimal") : 5, 
        ("Decimal", "Binary") : 6, 
     }.get((numeral_sys_1, numeral_sys_2), 0)

Ada juga yang menggunakan generator bisa jadi solusinya. Terlihat jauh lebih pintar, tapi saya pikir kamus kode keras akan lebih cepat daripada menggunakan generator untuk kebutuhan sederhana ini.


Interpretasi saya tentang 'else: return 0' yang terakhir adalah bahwa argumennya tidak cocok dan bisa menjadi sesuatu yang lain selain yang ada dalam daftar (mis. Kunci dikt Anda).
tocode

@ kode Ya, Anda benar. Tetapi metode ini juga menyediakan fungsionalitas yang sama. Jika ada atau kedua argumen yang diberikan kepada metode, katakanlah, bukan string, bahkan menjadi nilai jenis None; .get () metode mengembalikan "0" karena kurangnya kunci dalam kamus. Sederhana bukan?
Sencer H.

bukankah Anda hanya menyalin jawaban Aryerez?
Martin

@ Martin Tidak, saya tidak. Anda jelas tidak mengerti intinya. Ada banyak cara untuk melakukan sesuatu tetapi mengajarkan cara yang benar adalah apa yang ingin saya lakukan di sini. Sebenarnya ada jawaban yang jauh lebih baik di bawah ini. Lihatlah solusi furkanayd. Ini sempurna dan harus mendapatkan karunia.
Sencer H.

@ SencerH. Satu-satunya perbedaan adalah bahwa Anda menggunakan metode dict's get () yang pada dasarnya apa yang coba / kecuali jawaban asli lakukan. Anda tidak dapat menyangkal fakta, bahwa Anda menyalin ide dan sangat sedikit (tanpa perbaikan) dimodifikasi dan diterbitkan
Martin

3

Cara alternatif menggunakan daftar bersarang. Semoga ini bisa membantu !!

def convert_what(numeral_sys_1, numeral_sys_2):

    l1 = [["Hexadecimal","Decimal"],["Hexadecimal","Binary"],
            ["Decimal","Hexadecimal"],["Decimal","Binary"],
            ["Binary","Hexadecimal"],["Binary","Decimal"]]

    return l1.index([numeral_sys_1, numeral_sys_2]) + 1 if [numeral_sys_1,numeral_sys_2] in l1 else 0

2

Menurut pendapat saya, convert_whatfungsi ini sendiri tidak terlalu pythonic. Saya kira kode yang memanggil kode ini memiliki banyak pernyataan if juga dan melakukan konversi tergantung pada nilai balik convert_what(). Saya menyarankan sesuatu seperti ini:

Langkah pertama, buat satu fungsi untuk setiap kombinasi:

def hex_dec(inp):
    return 1234  # todo implement
# do the same for hex_bin, bin_dec, dec_hex, bin_hex, dec_bin

Langkah kedua, letakkan objek fungsi dalam dict. Perhatikan bahwa tidak ada () setelah nama fungsi, karena kami ingin menyimpan objek fungsi dan belum memanggilnya:

converter_funcs = {
    ("Hexadecimal", "Decimal"): hex_dec,
    ("Hexadecimal", "Binary"): hex_bin,
    ("Binary", "Decimal"): bin_dec,
    ("Decimal", "Hexadecimal"): dec_hex,
    ("Binary", "Hexadecimal"): bin_hex,
    ("Decimal", "Binary"): dec_bin,
}

Langkah ketiga dan terakhir, terapkan fungsi konversi. Pernyataan if memeriksa apakah kedua sistem itu sama. Kemudian, kita mendapatkan fungsi yang tepat dari dict kita dan menyebutnya:

def convert(input_number, from_sys, to_sys):
    if from_sys == to_sys:
        return input_number
    func = converter_funcs[(from_sys, to_sys)]
    return func(input_number)

2

Hal ini dilakukan oleh pernyataan peralihan kasus dalam sebagian besar bahasa lain. Dalam python, saya menggunakan fungsi sederhana dengan kamus ekspresi.

Kode:

def convert_what(numeral_sys_1, numeral_sys_2):
    myExpressions = {"Hexadecimal" : {"Decimal" : 1, "Binary" : 2},
                    "Decimal" : {"Hexadecimal" : 4, "Binary" : 6}, 
                    "Binary" : {"Hexadecimal" : 5, "Decimal" : 3}}
    return (myExpressions.get(numeral_sys_1, {})).get(numeral_sys_2, 0)

Keluaran:

> convert_what("Hexadecimal", "Decimal")
> 1
> convert_what("Binary", "Binary")
> 0
> convert_what("Invalid", "Hexadecimal")
> 0

ini adalah alternatif yang bagus untuk jawaban teratas dan lebih mudah untuk memperluas ke lebih banyak nilai juga.
gkhnavarro

Ini sangat mirip dengan jawaban sebelumnya: stackoverflow.com/a/58985114/1895261 . Juga, saya pikir baris terakhir harus mengembalikan dict kosong daripada 0 dalam hal numeral_sys_1 tidak berada di dict luar: return (myExpressions.get (numeral_sys_1, {})) get (numeral_sys_2, 0)
Sepia

@Sepia dalam pertanyaan Module_art memberikan 0 pada pernyataan else, yang berarti mengembalikan 0 apa pun tidak sesuai dengan ekspresi yang diberikan dan situasi kesetaraan.
furkanayd

1
Coba jalankan print (convert_what ("invalid", "Hexadecimal")) dengan kode Anda. Ini akan memunculkan kesalahan: "AttributeError: objek 'int' tidak memiliki atribut 'get'". Mengganti 0 pertama dengan dict kosong ({}) akan membuat fungsi mengembalikan 0 dengan benar dalam kasus numeral_sys_1 tidak valid.
Sepia

1

Secara umum saya akan menjalankan dengan solusi kamus untuk tugas bersarang jika. Beberapa kasus tertentu mungkin mengarah pada pendekatan lain. Seperti yang ini:

def convert_what(numeral_sys_1, numeral_sys_2):

    num = ['Hexadecimal','Decimal','Binary']
    tbl = [[0,1,2],
           [4,0,6],
           [5,3,0]]
    try:
        return tbl[num.index(numeral_sys_1)][num.index(numeral_sys_2)]
    except ValueError:
        return 0

1

Bagaimana dengan sesuatu seperti:

def convert_what(numeral_sys_1, numeral_sys_2):
    src = numeral_sys_1, numeral_sys_2
    if src == "Hexadecimal", "Decimal":
        return 1
    if src == "Hexadecimal", "Binary"
        return 2
    # You get the gist.... 
    if src == "Decimal", "Binary":
        return 6
    return 0 

1

Suatu Ide menggunakan daftar dan mendapatkan indeks hasil, yaitu.

def convert_what(numeral_sys_1, numeral_sys_2):
    if numeral_sys_1 == numeral_sys_2:      
        return 0
    return ["HexadecimalDecimal", "HexadecimalBinary", "BinaryDecimal", "DecimalHexadecimal", "BinaryHexadecimal", "DecimalBinary" ].index(numeral_sys_1 + numeral_sys_2) + 1

Saran yang menarik tetapi ini tidak berfungsi ketika argumennya adalah ("Desimal", "Tidak"), yang menghasilkan ValueError: 'DecimalNot' tidak ada dalam daftar
tocode

1

Seperti yang dikatakan @Sadap,

Menurut pendapat saya, convert_whatfungsi ini sendiri tidak terlalu pythonic. Saya kira kode yang memanggil kode ini memiliki banyak pernyataan if juga dan melakukan konversi tergantung pada nilai balik convert_what(). Saya menyarankan sesuatu seperti ini:

Jika Anda menerapkan konversi dasar untuk bilangan bulat, Anda mungkin akan melalui representasi umum pula: int. Fungsi terpisah untuk masing-masing pasangan pangkalan tidak diperlukan, dan kedua pangkalan yang terlibat bahkan tidak perlu saling mengenal.

Memasukkan

Buat pemetaan dari nama sistem angka ke dasarnya:

BINARY = "Binary"
DECIMAL = "Decimal"
HEXADECIMAL = "Hexadecimal"

BASES = {
    BINARY: 2,
    DECIMAL: 10,
    HEXADECIMAL: 16,
}

memungkinkan Anda membaca input dengan int(text, BASES[numeral_sys_1]).

Keluaran

Buat pemetaan dari nama sistem angka ke penentu format :

FORMATTERS = {
    BINARY: "b",
    DECIMAL: "d",
    HEXADECIMAL: "x",
}

memungkinkan Anda untuk menulis output dengan format(n, FORMATTERS[numeral_sys_2]).

Contoh penggunaan

def convert(text, numeral_sys_1, numeral_sys_2):
    n = int(text, BASES[numeral_sys_1])
    return format(n, FORMATTERS[numeral_sys_2])

Entah dikt juga dapat dibuat lebih umum dengan membuat fungsi nilai sebagai gantinya, jika Anda perlu mendukung serangkaian format yang berbeda dari int(x, base), atau lebih banyak basis output daripada dukungan format integer bawaan.


0

Saya suka menjaga kode tetap kering:

def convert_what_2(numeral_sys_1, numeral_sys_2):
    num_sys = ["Hexadecimal", "Decimal", "Binary"]
    r_value = {0: {1: 1, 2: 2},
               1: {0: 4, 2: 6},
               2: {0: 5, 1: 3} }
    try:
        value = r_value[num_sys.index(numeral_sys_1)][num_sys.index(numeral_sys_2)]
    except KeyError: # Catches when they are equal or undefined
        value = 0
    return value

0

Menggunakan beberapa teknik yang disediakan oleh jawaban lain dan menggabungkannya:

def convert(key1, key2):
    keys = ["Hexadecimal", "Decimal", "Binary"]
    combinations = {(0, 1): 1, (0, 2): 2, (1, 0): 4, (1, 2): 6, (2, 0): 5, (2, 1): 3} # use keys indexes to map to combinations
    try:
        return combinations[(keys.index(key1), keys.index(key2))]
    except (KeyError, ValueError): # if value is not in list, return as 0
        return 0

-1

Meski tidak yakin apakah pendekatan ini lebih cepat, tetapi bisa dilakukan dengan menggunakan numpy juga:

conditions = [
    ("Hexadecimal", "Decimal"), ("Hexadecimal", "Binary"),
    ("Binary", "Decimal"), ("Decimal", "Hexadecimal"), ("Binary", "Hexadecimal"), ("Decimal", "Binary")]
choices = [1,2,3,4,5,6]

dan dapat digunakan sebagai:

 np.select(conditions, choices, default=0)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.