Python'da iç içe if ifadeleri yazmanın daha iyi bir yolu var mı? [kapalı]


34

Bu ifadeden başka ifadeler iç içe yerleştirmenin daha pythonic bir yolu var mı:

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

Bu komut dosyası basit bir dönüştürücünün bir parçasıdır.


Başka bir veri yapısı kullanmadan, iç içe if-else deyimlerini anden üst düzey if-else deyimlerinin koşullarına taşıyabilirsiniz . En azından bu şekilde daha okunabilir olurdu. Ne yazık ki, python'un anahtar ifadeleri yok.
adamkgray

Bu ise pythonic yolu. Python kasıtlı olarak switch deyimlerini desteklemez. Bkz. Python.org/dev/peps/pep-3103
Jongmin Baek

1
Hiç soru değil, ama bir şeyleri daha Pythonic yapmaya çalışıyorsanız, sabit değerleri ya da dönüş değerleri için bir numaralandırma tanımlamaya ne dersiniz - bir okuyucu için "sihirli sayılar" dan daha hoş ....
Mats Wichmann

Yanıtlar:


13

@Aryerez ve @ SencerH.'nin cevapları çalışırken, olası değerlerin sayısı arttığında veri yapısının korunmasını zorlaştırarak, değer çiftlerini listelemenin numeral_sys_1olası her değeri için tekrar tekrar yazılması gerekir numeral_sys_2. Bunun yerine, iç içe if ifadelerinizin yerine iç içe geçmiş bir dikte kullanabilirsiniz:

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)

Alternatif olarak, itertools.permutationssırası ile giriş sırasının sırasını izleyen yöntemle eşleştirme için değer çiftleri oluşturabilirsiniz :

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

Bir üzere tüm geçerli kombinasyonları yerleştirin dictionaryve tuples, ve kombinasyon yoksa return 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)

İşlevi bir döngüde kullanmayı planlıyorsanız, sözlüğü işlevin dışında tanımlamak daha iyi bir fikir olabilir, bu nedenle işleve yapılan her çağrıda yeniden oluşturulmaz.


2
except KeyError:
RomanPerekhrest

@RomanPerekhrest Ekledim, bu özel soruda, işlevin kendisinin orijinal işlevinden farklı bir çıktı verecek başka hata türleri üretmiyor.
Aryerez

1
Parenler [] içinde gereksizdir. Boş demet dışında, parantez değil, bir demet yapan virgül bu, bazı durumlarda işlem sırası içindir.
gilch

4
Dict .get()yöntemini deyim 0yerine varsayılan olarak kullanabilirsiniz try.
gilch

@gilch Parantezleri düşürdüm. Ama try:... except:...yapıyı seviyorum .
Aryerez

17

Numeral_sys_1 ve numeral_sys_2 değişkenlerine ayarlanmış başka bir değer olmadığından eminseniz, bu en basit ve en temiz çözümdür.

Öte yandan, "Onaltılık", "Ondalık" ve "İkili" dışında bir değeriniz varsa sözlüğü kullanılabilir değerlerle kombinasyonlarıyla genişletmeniz gerekir.

Buradaki mantık; sözlük anahtarlarındaki değişken tuples verilen değişken tuple ile eşit değilse, .get () yöntemi "0" değerini döndürür. Verilen değişken tuple sözlükteki herhangi bir anahtarla eşleşirse, eşleşen anahtarın değerini döndürün.

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)

Jeneratör kullanmak da bir çözüm olabilir. Çok daha akıllıca görünüyor, ancak sabit kodlu sözlüğün bu basit gereksinim için bir jeneratör kullanmaktan daha hızlı olacağını düşünüyorum.


Son 'else: return 0' hakkındaki yorumum, argümanların eşleşmediği ve listedekilerin yanında başka bir şey olabileceği (yani, dict anahtarlarınız).
tocode

@tocode Evet, haklısın. Ancak bu yöntem de aynı işlevselliği sağlamaktır. Yönteme verilen argümanlardan herhangi biri veya her ikisi de diyelim, dize değil, hatta Hiçbiri tür değeri; .get () yöntemi, sözlükteki anahtar eksikliğinden dolayı "0" döndürür. Basit değil mi?
Sencer H.

Aryerez cevabını kopyaladın mı?
Martin

@Martin Hayır yapmadım. Bu noktayı açıkça kaçırıyorsunuz. Bir şey yapmanın birçok yolu var ama doğru yolu öğretmek burada yapmak istediğim şey. Aslında aşağıda çok daha iyi bir cevap var. Furkanayd'ın çözümüne bir göz atın. Kusursuz ve lütuf almak zorunda kaldı.
Sencer H.

Tek fark, orijinal yanıtın denemesi / hariç tuttuğu şey olan dict yönteminin get () yöntemini kullanmanızdı. Bu fikri inkar edemezsiniz, fikri kopyaladınız ve çok hafifçe (gelişmeden) değiştirildi ve yayınlandı
Martin

3

İç içe liste kullanarak alternatif bir yol. Umarım yardımcı olur!!

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

Bence bu convert_whatfonksiyonun kendisi çok pitonik değil. Bu kod çağıran kodu if ifadeleri bir sürü var ve dönüş değerine bağlı olarak dönüştürme yapar sanırım convert_what(). Böyle bir şey öneririm:

İlk adım, her kombinasyon için bir işlev yapın:

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

İkinci adım, fonksiyon nesnelerini bir dikteye koyun. İşlev adlarından sonra no () olmadığını unutmayın, çünkü işlev nesnesini saklamak ve henüz çağırmamak istiyoruz:

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,
}

Üçüncü ve son adım, bir dönüştürme işlevi uygulayın. İf ifadesi her iki sistemin de aynı olup olmadığını kontrol eder. Ardından, doğru işlevi diktemizden alıyoruz ve çağırıyoruz:

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

Bu, diğer dillerin çoğunda anahtar durum ifadeleriyle yapılır. Python'da, bir ifade sözlüğü ile basit bir işlev kullanıyorum.

Kod:

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)

Çıktı:

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

bu en iyi cevaba iyi bir alternatiftir ve daha fazla değere genişletmek daha kolaydır.
gkhnavarro

Bu önceki bir cevaba oldukça benziyor: stackoverflow.com/a/58985114/1895261 . Ayrıca, numeral_sys_1 dış dikte olmadığı durumda son satırın 0 yerine boş diksiyonu döndürmesi gerektiğini düşünüyorum: dönüş (myExpressions.get (numeral_sys_1, {})). Get (numeral_sys_2, 0)
Sepya

@ Module_art sorusundaki Sepia, else ifadesinde 0 verir, bu da 0 döndürme ifadesinin verilen ifadelere ve eşitlik durumuna uymadığı anlamına gelir.
furkanayd

1
Kodunuzla print (convert_what ("geçersiz", "Onaltılık")) çalıştırmayı deneyin. Bir hata oluşturur: "AttributeError: 'int' nesnesinin 'get' özelliği yok." İlk 0'ın boş dikteyle ({}) değiştirilmesi, numeral_sys_1 geçersiz olduğunda işlevin doğru 0 döndürmesini sağlar.
Sepya

1

Genel olarak ben görev iç içe için sözlük çözüm ile çalışır. Bazı özel durumlar başka bir yaklaşıma yol açabilir. Bunun gibi:

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

Nasıl bir şey hakkında:

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

Bir Fikir bir liste kullanır ve sonuç dizini almak, yani.

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

İlginç bir öneri ancak argümanlar ("Ondalık", "Not") olduğunda işe yaramaz, bu da ValueError ile sonuçlanır: 'DecimalNot' listede değil
7'de kodlamak

1

@Sadap'ın dediği gibi,

Bence bu convert_whatfonksiyonun kendisi çok pitonik değil. Bu kod çağıran kodu if ifadeleri bir sürü var ve dönüş değerine bağlı olarak dönüştürme yapar sanırım convert_what(). Böyle bir şey öneririm:

Eğer tamsayılar için taban dönüşümünü uyguluyorsanız, muhtemelen yine ortak bir temsil yoluyla gidiyoruz: int. Her baz çifti için ayrı bir fonksiyon gerekli değildir ve dahil olan iki bazın birbirlerini bilmesine bile gerek yoktur.

Giriş

Bir sayı sisteminin adından tabanına bir eşleme oluşturun:

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

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

ile girişleri okumanıza izin verir int(text, BASES[numeral_sys_1]).

Çıktı

Sayı sisteminin adından format belirleyicisine eşleme oluşturun :

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

ile çıktılar yazmanıza izin verir format(n, FORMATTERS[numeral_sys_2]).

Örnek kullanım

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

Bunun yerine, farklı bir biçim kümesini desteklemeniz gerekiyorsa int(x, base)ya da yerleşik tamsayı biçimlendirme desteklerinden daha fazla çıkış temelleri gerekiyorsa, her iki değer de daha genel değerler yapılabilir .


0

Kodu kuru tutmak istiyorum:

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

Diğer cevapların sağladığı bazı teknikleri kullanarak bunları birleştirin:

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

Bu yaklaşımın daha hızlı olup olmadığından emin olmasa da, numpy kullanılarak da yapılabilir:

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

ve şu şekilde kullanılabilir:

 np.select(conditions, choices, default=0)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.