Pythonでネストされたifステートメントを書くより良い方法はありますか?[閉まっている]


34

これよりもネストされたif elseステートメントを行うためのよりPython的な方法はありますか?

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にはswitchステートメントがありません。
adamkgray

これ pythonicの方法です。Pythonは意図的にswitchステートメントをサポートしていません。python.org/dev/peps/pep-3103を
Jongmin Baek

1
まったく問題ではありませんが、物事をよりPythonicにしようとしている場合は、定数または戻り値の列挙型を定義してみてください。「マジックナンバー」よりも読み手に適しています...
Mats Wichmann

回答:


13

@Aryerezと@SencerH。の回答は機能しますが、可能な各値は、可能な各値に対してnumeral_sys_1繰り返し書き込まれる必要があります。numeral_sys_2、値のペアをリストする場合、の数が増えると、データ構造の維持が難しくなります。代わりに、ネストされたifステートメントの代わりにネストされたdictを使用できます。

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

すべての有効な組み合わせの挿入dictionaryのをtuple S、及び組み合わせが存在しない場合は、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追加しましたが、この特定の質問では、関数自体には、元の関数とは異なる出力を生成する他のタイプのエラーはありません。
Aryerez

1
括弧は[]内で冗長です。空のタプルを除いて、かっこではなく、それをタプルにするのはコンマです。これは、場合によっては操作の順序のためだけです。
ギルチ

4
ステートメントの代わりに、デフォルトでdict .get()メソッドを使用でき0ますtry
ギルチ

@gilch括弧を落としました。しかし、私はtry:... except:...構造が好きです。
Aryerez

17

他に値がないことが確かである場合は、numeric_sys_1変数およびnumeric_sys_2変数に設定されている可能性があり、これが最も簡単で最もクリーンなソリューションです。

一方、「16進数」、「10進数」、「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」を返します。簡単ではないですか?
Sencer H.

Aryerezの回答をコピーしただけですか?
マーティン

@Martinいいえ、しませんでした。あなたは明らかにポイントを逃しています。何かをする方法はたくさんありますが、正しい方法を教えることが私がここでやる気があることです。実際には、以下のより良い答えがあります。furkanaydのソリューションを見てください。それは完璧であり、賞金をもらう必要がありました。
Sencer H.

@SencerH。唯一の違いは、元の答えのtry / exceptが基本的に行うdictのメソッドget()を使用したことです。アイデアをコピーし、ごくわずかに(改善せずに)修正して公開したという事実を否定することはできません
Martin

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関数自体はそれほどPythonicではありません。私はこのコードを呼び出すコードにもたくさんのifステートメントがあり、の戻り値に応じて変換を行うと思いますconvert_what()。私はこのようなものを提案します:

最初のステップでは、すべての組み合わせに対して1つの関数を作成します。

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

3番目と最後のステップで、変換関数を実装します。ifステートメントは、両方のシステムが同じかどうかを確認します。次に、dictから適切な関数を取得して呼び出します。

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

これは、他のほとんどの言語のswitch-caseステートメントによって行われます。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。また、numeric_sys_1が外側の辞書にない場合、最後の行は0ではなく空の辞書を返す必要があると思います:return(myExpressions.get(numeral_sys_1、{}))。get(numeral_sys_2、0)
Sepia

質問Module_artの@Sepiaは、elseステートメントで0を返します。これは、0を返すことは、与えられた式および同等の状況に適合しないものを意味します。
フルカナイド

1
コードでprint(convert_what( "invalid"、 "Hexadecimal"))を実行してみてください。「AttributeError: 'int' object has no attribute 'get'」というエラーが発生します。最初の0を空の辞書({})で置き換えると、関数numeric_sys_1が無効な場合に関数が正しく0を返します。
Sepia

1

一般的に、ネストされたifタスクの辞書ソリューションを使用して実行します。いくつかの特定のケースは別のアプローチをもたらすかもしれません。このように:

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

興味深い提案ですが、引数が( "Decimal"、 "Not")の場合、これは機能せず、ValueError: 'DecimalNot'はリストにありません
tocode

1

@Sadapが言ったように、

私の意見では、このconvert_what関数自体はそれほどPythonicではありません。このコードを呼び出すコードにもifステートメントがたくさんあり、の戻り値に応じて変換を行うと思いますconvert_what()。私はこのようなものを提案します:

整数の基本変換を実装している場合は、とにかく一般的な表現をたどることになりますint。塩基のペアごとに個別の関数を使用する必要はなく、関係する2つの塩基は互いについて知る必要さえありません。

入力

数体系の名前からその基数へのマッピングを作成します。

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)、または組み込みの整数フォーマットがサポートするよりも多くの出力ベースをサポートする必要がある場合は、代わりに値関数を作成することにより、どちらのdictもより一般的にすることができます。


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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.