1. ホーム
  2. スクリプト・コラム
  3. パイソン

Pythonのデコレーターを巧みに使ってif...elif...elseを処理する

2022-01-27 10:14:56

この方法がどのようなものか、具体的に見てみましょう。例えば、ユーザーのランクに応じて、そのユーザーが受けられる割引を決める関数を作りたいとします。通常のif ... elif ... は、このように書くことになる。

def get_discount(level):
    if level == 1:
        "Bulk calculation code"
        discount = 0.1
    elif level == 2:
        "Bulk calculation code"
        discount = 0.2
    elif level == 3:
        discount = 0.3
    elif level == 4:
        discount = 0.4
    elif level == 5:
        discount = 0.5
    elif level == 6:
        discount = 3 + 2 - 5 * 0.1
    else:
         return 'Level error'
    return discount


ご存知のように、このような大量の if ... elif... のコードは非常に見づらく、メンテナンスも大変です。そして、それぞれのifの内部にはたくさんのコードがあります。そうすると、関数がとても長く引き延ばされてしまいます。

この長すぎるif判定を辞書を使って書き換えることができることを知っている学生もいます。

def parse_level_1():
    "Bulk calculation code"
    discount = 0.1
    return discount

def parse_level_2():
    "Bulk calculation code"
    discount = 0.2
    return discount

def parse_level_3():
    "Bulk calculation code"
    discount = 0.3
    return discount

def parse_level_4():
    "Bulk calculation code"
    discount = 0.4
    return discount

def parse_level_5():
    "Bulk calculation code"
    discount = 0.5
    return discount

def parse_level_6():
    "Bulk calculation code"
    discount = 3 + 2 - 5 * 0.1
    return discount

discount_map = {
 1: parse_level_1,
  2: parse_level_2,
  3: parse_level_3,
  4: parse_level_4,
  5: parse_level_5,
  6: parse_level_6,
}

discount = discount_map.get(level, 'level error')


でも、今日習ったこの方法は、辞書を使うよりも簡単なんだ。その方法を見てみましょう。

@value_dispatch
def get_discount(level):
    return 'Level error'

@get_discount.register(1)
def parse_level_1(level):
    "Bulk calculation code"
    discount = 0.1
    return discount

@get_discount.register(2)
def parse_level_2(level):
    "Bulk calculation code"
    discount = 0.2
    return discount

@get_discount.register(3)
def parse_level_3(level):
    "Bulk calculation code"
    discount = 0.3
    return discount

@get_discount.register(4)
def parse_level_4(level):
    "Bulk calculation code"
    discount = 0.4
    return discount

@get_discount.register(5)
def parse_level_5(level):
    "Bulk calculation code"
    discount = 0.5
    return discount

@get_discount.register(6)
def parse_level_1(level):
    "Bulk calculation code"
    discount = 3 + 2 - 5 * 0.1
    return discount


discount = get_discount(3)
print(f'The user with level 3, the discount received is: {discount}')


実行結果は、以下の画像のようになります。

このように書くと、辞書を使うよりも直感的で、単に if ... elif... はより簡潔です。

そこで、このデコレータ value_dispatch どのように実装されているのでしょうか?パスワードは、このオープンソースプロジェクトに隠されています。 EdgeDB のソースコード[2]にある、20行強のコアコードで構成されています。

そして、それを実装したり、問い合わせることも可能です。例えば、ユーザーレベルが2または3で、割引が0.2の場合、以下のようにコードを記述することができます。

@get_discount.register(2)
@get_discount.register(3)
def parse_level_2(level):
    "Bulk calculation code"
    discount = 0.2
    return discount


実行結果は、以下の画像のようになります。

このコードでは、現在、イコールクエリしかできません。しかし、実はこのコードに少し手を加えるだけで、より大きい、より小さい、以上、以下、以下、等しくない、そして in といった具合です。もし興味があれば、記事の下にコメントを残してください。明日、このコードを修正してより論理的な判定を実装する方法についてお話します。

参考文献

[1] EdgeDB。 https://github.com/edgedb/edgedb

[2] ソースコード https://github.com/edgedb/edgedb/blob/master/edb/common/value_dispatch.py

技術交流

転載、ブックマーク、応援よろしくお願いします。

Pythonのデコレータを巧みに使ってif. .elif.. ...elseを処理する記事はこちらで紹介していますが、もっと関連するPythonデコレータのコンテンツは、スクリプトハウスの過去の記事を検索してください。