Чи є кращий спосіб написати вкладені, якщо заяви в python? [зачинено]


34

Чи є більш пітонічний спосіб зробити вкладені, якщо інші заяви, ніж цей:

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

Цей сценарій є частиною простого перетворювача.


Не використовуючи іншої структури даних, ви можете перемістити вкладені оператори if-else в andумови для операторів вищого рівня if-else. Принаймні, так було б читабельніше. На жаль, у python немає тверджень перемикача.
adamkgray

Це є віщим шляхом. Python навмисно не підтримує оператори переключення. Дивіться python.org/dev/peps/pep-3103
Jongmin Baek

1
Зовсім не питання, але якщо ви намагаєтесь зробити речі більш пітонічними, як щодо визначення констант або перерахунку на повернені значення - приємніше для читача, ніж "магічні числа" ....
Матс Віхман

Відповіді:


13

Хоча відповіді @Aryerez і @ SencerH. Працюють, кожне можливе значення numeral_sys_1має бути повторно записане для кожного можливого значення numeral_sys_2при переліку пар значень, що ускладнює підтримку структури даних, коли кількість можливих значень збільшується. Натомість ви можете використовувати вкладений дікт замість вкладеного файлу, якщо натомість:

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)

Крім того, ви можете генерувати пари значень для відображення за допомогою itertools.permutationsметоду, порядок якого випливає з послідовності введення:

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

Вставте всі дійсні комбінації в a dictionaryз tuples, а якщо комбінації немає, поверніть 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)

Якщо ви плануєте використовувати функцію в циклі, може бути кращою ідеєю визначити словник поза функцією, тому він не буде відтворений під час кожного виклику функції.


2
except KeyError:
RomanPerekhrest

@RomanPerekhrest Я додав це, хоча у цьому конкретному питанні сама функція не має інших типів помилок , які б давали різні результати від його початкової функції.
Ар'єрез

1
Парени зайві всередині []. За винятком порожнього кортежу, коска робить його кортежем, а не дужки, це лише для порядку операцій в деяких випадках.
gilch

4
Ви можете просто використовувати .get()метод dict із 0замовчуванням замість tryоператора.
gilch

@gilch Я скинув дужки. Але мені подобається try:... except:...структура.
Ар'єрес

17

Якщо ви впевнені, що інше значення не могло бути встановлено для змінних numeral_sys_1 та numeral_sys_2, це найпростіше і найпростіше рішення.

З іншого боку, ви маєте розширити словник на його комбінації з доступними значеннями, якщо у вас є якесь інше значення, ніж "Шістнадцятковий", "Десятковий" та "Двійковий"

Логіка тут така; якщо змінні кортежі в клавішах словника не рівні заданому кортежу змінної, метод .get () повертає "0". Якщо заданий змінний кортеж відповідає будь-якій клавіші в словнику, то повертається значення відповідного ключа.

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)

Існує також використання генератора, яке може бути рішенням. Виглядає набагато розумнішим, але я думаю, що важко закодований словник був би швидшим, ніж використання генератора для цієї простої вимоги.


Моя інтерпретація останнього "else: return 0" полягає в тому, що аргументи не збігаються і можуть бути чимось іншим поруч із тими у списку (т. Е. Вашими клавішами dict).
кодувати

@tocode Так, ви праві. Але цей метод також забезпечує таку ж функціональність. Якщо будь-який або обидва аргументи, наведені методу, скажімо, не є рядковими, навіть не мають значення типу None; Метод .get () повернення "0" через відсутність ключа в словнику. Хіба це не просто?
Сенсер Х.

ти не просто скопіював відповідь Ар'єреса?
Мартін

@Martin Ні, я цього не робив. Ви чітко пропускаєте суть. Є багато способів зробити щось, але викладати правильний спосіб - це те, що я хочу зробити тут. Насправді є набагато краща відповідь нижче. Погляньте на рішення фурканайда. Це бездоганно, і його потрібно було отримати щедро.
Sencer H.

@ SencerH. Єдина відмінність полягала в тому, що ви використовували метод dict get (), що принципово є оригінальною спробою відповіді / за винятком. Ви не можете заперечувати той факт, що ви скопіювали ідею і дуже мало (без вдосконалення) модифікували та опублікували
Мартін

3

Альтернативний спосіб використання вкладеного списку. Сподіваюся, це допомагає !!

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

На мою думку, ця convert_whatфункція сама по собі не дуже пітонічна. Я здогадуюсь, що код, який викликає цей код, має купу if операторів теж і робить перетворення залежно від значення, що повертаєтьсяconvert_what() . Я пропоную щось подібне:

Перший крок, зробіть одну функцію для кожної комбінації:

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

Другий крок, покладіть об'єкти функцій у дікт. Зауважте, що після імен функцій немає (), оскільки ми хочемо зберегти об'єкт функції, а не викликати його ще:

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

Третій і останній крок, реалізуйте функцію перетворення. Оператор if перевіряє, чи обидві системи однакові. Тоді ми отримуємо правильну функцію з нашої картини і називаємо її:

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

Це робиться за допомогою операторів перемикання випадку на більшості інших мов. У python я використовую просту функцію зі словником виразів.

Код:

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)

Вихід:

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

це хороша альтернатива верхній відповіді, і простіше також поширюватися на більше значень.
gkhnavarro

Це досить схоже на попередню відповідь: stackoverflow.com/a/58985114/1895261 . Крім того, я думаю, що останній рядок повинен повертати порожній дикт, а не 0 у випадку, якщо numeral_sys_1 не знаходиться у зовнішньому диктаті: return (myExpressions.get (numeral_sys_1, {})). Get (numeral_sys_2, 0)
Sepia

@Sepia у запитанні Module_art дає 0 у висловленні else, а це означає, що return 0 нічого не відповідає викладеним виразам та ситуації рівності.
furkanayd

1
Спробуйте виконати print (convert_what ("недійсний", "Шістнадцятковий")) зі своїм кодом. Це призведе до помилки: "AttributeError:" int "об'єкт не має атрибута" get "". Якщо замінити перший 0 порожнім диктом ({}), функція вірно поверне 0 у випадку, коли номер_sys_1 недійсний.
Sepia

1

Взагалі я би працював із словниковим рішенням для вкладених, якщо завдання. Деякі конкретні випадки можуть призвести до іншого підходу. Як ця:

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

Як щодо чогось такого:

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

Ідея використовує список і отримує індекс результату, тобто.

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

Цікава пропозиція, але це не спрацьовує, коли аргументи ("Десятковий", "Не"), в результаті яких ValueError: "DecimalNot" немає в списку
кодувати

1

Як сказав @Sadap,

На мою думку, ця convert_whatфункція сама по собі не дуже пітонічна. Я здогадуюсь, що код, який викликає цей код, має купу if операторів теж і робить перетворення залежно від значення, що повертаєтьсяconvert_what() . Я пропоную щось подібне:

Якщо ви здійснюєте базову конверсію для цілих чисел, ви, ймовірно, все одно переживаєте загальне представлення: int . Окрему функцію для кожної пари баз не потрібно, і дві задіяні бази навіть не повинні знати один про одного.

Вхідні дані

Створіть відображення з назви системи числення до її бази:

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

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

що дозволяє читати вхідні дані за допомогою int(text, BASES[numeral_sys_1]) .

Вихідні дані

Створіть зіставлення із імені системи числення до специфікатора формату :

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

що дозволяє писати виходи за допомогою format(n, FORMATTERS[numeral_sys_2]) .

Приклад використання

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

Будь-який диктат може бути також більш загальним, замість того, щоб зробити значення значень натомість, якщо вам потрібно підтримувати інший набір форматів, ніж int(x, base)або більше вихідних баз, ніж вбудовані цілі підтримки форматування.


0

Мені подобається зберігати код сухим:

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

Використовуючи деякі прийоми, які надають інші відповіді, та поєднайте їх:

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

Хоча не впевнений, чи такий підхід швидший, але це можна зробити і за допомогою numpy:

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

і може використовуватися як:

 np.select(conditions, choices, default=0)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.