Gibt es eine bessere Möglichkeit, verschachtelte if-Anweisungen in Python zu schreiben? [geschlossen]

34

Gibt es eine pythonischere Möglichkeit, verschachtelte if else-Anweisungen als diese auszuführen:

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

Dieses Skript ist Teil eines einfachen Konverters.

Module_art
quelle
Ohne Verwendung einer anderen Datenstruktur können Sie die verschachtelten if-else-Anweisungen in andBedingungen für die if-else-Anweisungen der obersten Ebene verschieben. Zumindest wäre es so besser lesbar. Leider hat Python keine switch-Anweisungen.
Adamkgray
Dies ist der pythonische Weg. Python unterstützt absichtlich keine switch-Anweisungen. Siehe python.org/dev/peps/pep-3103
Jongmin Baek
1
Überhaupt nicht die Frage, aber wenn Sie versuchen, die Dinge pythonischer zu gestalten, wie wäre es, wenn Sie Konstanten oder eine Aufzählung für die Rückgabewerte definieren - schöner für einen Leser als "magische Zahlen" ...
Mats Wichmann

Antworten:

13

Während die Antworten von @Aryerez und @ SencerH. funktionieren, muss jeder mögliche Wert von numeral_sys_1wiederholt für jeden möglichen Wert von numeral_sys_2bei der Auflistung der Wertepaare geschrieben werden, was es schwieriger macht, die Datenstruktur beizubehalten, wenn die Anzahl der möglichen Werte zunimmt. Sie können stattdessen ein verschachteltes Diktat anstelle Ihrer verschachtelten if-Anweisungen verwenden:

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)

Alternativ können Sie die Wertepaare für das Mapping mit der itertools.permutationsMethode generieren , deren Reihenfolge der der Eingabesequenz folgt:

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)
blhsing
quelle
29

Fügen Sie alle gültigen Kombinationen in a dictionaryvon tuples ein. Wenn die Kombination nicht vorhanden ist, geben Sie 0 zurück:

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)

Wenn Sie die Funktion in einer Schleife verwenden möchten, ist es möglicherweise besser, das Wörterbuch außerhalb der Funktion zu definieren, damit es nicht bei jedem Aufruf der Funktion neu erstellt wird.

Aryerez
quelle
2
except KeyError:
RomanPerekhrest
@RomanPerekhrest Ich habe es hinzugefügt, obwohl in dieser speziellen Frage die Funktion selbst keine anderen Arten von Fehlern zu erzeugen hat, die eine andere Ausgabe als seine ursprüngliche Funktion ergeben würden.
Aryerez
1
Die Parens sind in [] überflüssig. Mit Ausnahme des leeren Tupels ist es das Komma, das es zu einem Tupel macht, nicht die Klammern, sondern in einigen Fällen nur die Reihenfolge der Operationen.
Gilch
4
Sie können anstelle der Anweisung einfach die Standardmethode dict .get()verwenden . 0try
Gilch
@ Gilch Ich habe die Klammern fallen lassen. Aber ich mag die try:... except:...Struktur.
Aryerez
17

Wenn Sie sicher sind, dass kein anderer Wert auf die Variablen numeral_sys_1 und numeral_sys_2 festgelegt wurde, ist dies die einfachste und sauberste Lösung.

Andererseits müssen Sie das Wörterbuch mit seinen Kombinationen mit verfügbaren Werten erweitern, wenn Sie einen anderen Wert als "Hexadezimal", "Dezimal" und "Binär" haben.

Die Logik hier ist; Wenn variable Tupel in Wörterbuchschlüsseln nicht dem angegebenen variablen Tupel entsprechen, gibt die Methode .get () "0" zurück. Wenn ein variables Tupel mit einem beliebigen Schlüssel im Wörterbuch übereinstimmt, wird der Wert des übereinstimmenden Schlüssels zurückgegeben.

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)

Es könnte auch die Verwendung eines Generators eine Lösung sein. Sieht viel schlauer aus, aber ich denke, ein hartcodiertes Wörterbuch wäre schneller als die Verwendung eines Generators für diese einfache Anforderung.

Sencer H.
quelle
Meine Interpretation des letzten 'else: return 0' ist, dass die Argumente nicht übereinstimmen und etwas anderes als die in der Liste aufgeführten sein könnten (dh Ihre Diktatschlüssel).
tocode
@tocode Ja, du hast recht. Diese Methode bietet jedoch auch die gleiche Funktionalität. Wenn eines oder beide Argumente für die Methode angegeben werden, z. B. kein String, auch wenn es sich um einen Wert vom Typ None handelt. Die Methode .get () gibt "0" zurück, da der Schlüssel im Wörterbuch fehlt. Ist es nicht einfach?
Sencer H.
Hast du nicht einfach die Antwort von Aryerez kopiert?
Martin
@ Martin Nein, habe ich nicht. Sie verpassen eindeutig den Punkt. Es gibt viele Möglichkeiten, etwas zu tun, aber ich bin bereit, hier richtig zu lehren. Eigentlich gibt es unten eine viel bessere Antwort. Schauen Sie sich die Lösung von furkanayd an. Es ist einwandfrei und musste Kopfgeld bekommen.
Sencer H.
@ SencerH.Der einzige Unterschied war, dass Sie die Methode get () von dict verwendet haben. Dies ist im Grunde das, was der Versuch / die Ausnahme der ursprünglichen Antwort bewirkt. Sie können die Tatsache nicht leugnen, dass Sie Idee kopiert und sehr, sehr leicht (ohne zu verbessern) modifiziert und veröffentlicht haben
Martin
3

Eine alternative Möglichkeit, verschachtelte Listen zu verwenden. Ich hoffe es hilft!!

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
Sapan Zaveri
quelle
2

Meiner Meinung nach ist diese convert_whatFunktion selbst nicht sehr pythonisch. Ich denke, der Code, der diesen Code aufruft, hat auch eine Reihe von if-Anweisungen und konvertiert abhängig vom Rückgabewert von convert_what(). Ich schlage so etwas vor:

Machen Sie im ersten Schritt eine Funktion für jede Kombination:

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

Im zweiten Schritt setzen Sie die Funktionsobjekte in ein Diktat. Beachten Sie, dass nach den Funktionsnamen kein () steht, da das Funktionsobjekt gespeichert und noch nicht aufgerufen werden soll:

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

Im dritten und letzten Schritt implementieren Sie eine Konvertierungsfunktion. Die if-Anweisung prüft, ob beide Systeme identisch sind. Dann bekommen wir die richtige Funktion aus unserem Diktat und nennen es:

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)
Sadap
quelle
2

Dies erfolgt durch switch-case-Anweisungen in den meisten anderen Sprachen. In Python verwende ich eine einfache Funktion mit einem Ausdruckswörterbuch.

Code:

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)

Ausgabe:

> convert_what("Hexadecimal", "Decimal")
> 1
> convert_what("Binary", "Binary")
> 0
> convert_what("Invalid", "Hexadecimal")
> 0
furkanayd
quelle
Dies ist eine gute Alternative zur Top-Antwort und es ist einfacher, sich auch auf mehr Werte auszudehnen.
Gkhnavarro
Dies ist einer vorherigen Antwort ziemlich ähnlich: stackoverflow.com/a/58985114/1895261 . Ich denke auch, dass die letzte Zeile das leere Diktat anstelle von 0 zurückgeben sollte, falls sich numeral_sys_1 nicht im äußeren Diktat befindet: return (myExpressions.get (numeral_sys_1, {})). Get (numeral_sys_2, 0)
Sepia
@Sepia in der Frage Module_art gibt bei der else-Anweisung 0 an, was bedeutet, dass 0 zurückgegeben wird. Alles stimmt nicht mit den angegebenen Ausdrücken und der Gleichheitssituation überein.
Furkanayd
1
Versuchen Sie, print (convert_what ("ungültig", "hexadezimal")) mit Ihrem Code auszuführen. Es wird ein Fehler ausgegeben: "AttributeError: 'int' Objekt hat kein Attribut 'get'". Wenn Sie die erste 0 durch das leere Diktat ({}) ersetzen, gibt die Funktion 0 korrekt zurück, falls numeral_sys_1 ungültig ist.
Sepia
1

Im Allgemeinen würde ich mit Wörterbuchlösung für verschachtelte if-Aufgabe ausführen. Einige besondere Fälle können zu einem anderen Ansatz führen. Wie dieser:

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
Anatoliy R.
quelle
1

Wie wäre es mit so etwas wie:

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 
AnonymousAlex
quelle
1

Eine Idee verwendet eine Liste und erhält einen Index des Ergebnisses, dh.

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
keiner
quelle
Interessanter Vorschlag, aber dies funktioniert nicht, wenn Argumente ("Dezimal", "Nicht") sind, was zu ValueError führte: 'DecimalNot' ist nicht in der Liste
tocode
1

Wie @Sadap sagte,

Meiner Meinung nach ist diese convert_whatFunktion selbst nicht sehr pythonisch. Ich denke, der Code, der diesen Code aufruft, hat auch eine Reihe von if-Anweisungen und konvertiert abhängig vom Rückgabewert von convert_what(). Ich schlage so etwas vor:

Wenn Sie die Basiskonvertierung für Ganzzahlen implementieren, werden Sie wahrscheinlich trotzdem eine allgemeine Darstellung durchlaufen : int. Eine separate Funktion für jedes Basenpaar ist nicht erforderlich, und die beiden beteiligten Basen müssen nicht einmal voneinander wissen.

Eingang

Erstellen Sie eine Zuordnung vom Namen eines Zahlensystems zu seiner Basis:

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

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

So können Sie Eingaben mit lesen int(text, BASES[numeral_sys_1]).

Ausgabe

Erstellen Sie eine Zuordnung vom Namen eines Zahlensystems zu einem Formatbezeichner :

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

So können Sie Ausgaben mit schreiben format(n, FORMATTERS[numeral_sys_2]).

Beispiel Verwendung

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

Jedes Diktat kann auch allgemeiner gestaltet werden, indem stattdessen die Wertefunktionen verwendet werden, wenn Sie einen anderen Satz von Formaten als int(x, base)oder mehr Ausgabebasen als die integrierte Ganzzahlformatierung unterstützen müssen.

Ry-
quelle
0

Ich mag es, Code trocken zu halten:

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
Mikeologe
quelle
0

Verwenden Sie einige Techniken, die die anderen Antworten bieten, und kombinieren Sie sie:

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
Michael Yang
quelle
-1

Ich bin mir zwar nicht sicher, ob dieser Ansatz schneller ist, könnte aber auch mit numpy durchgeführt werden:

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

und kann verwendet werden als:

 np.select(conditions, choices, default=0)
vp7
quelle