きり丸の技術日記

技術検証したり、資格等をここに残していきます。

Pythonでメソッド呼び出し元がNoneパラメータを渡さないようにする(doesn't call none parameter in Python)

メソッド呼び出し元で引数が指定されていない場合は、デフォルト値を与えられます。キーワード引数を使用すると、任意のパラメータに値を与えられます。

ただし、意図的にメソッド呼び出し元でNoneを渡してしまった場合、デフォルト値を使用できません。

今回の記事では、パラメータの値がNoneの場合はメソッドに渡さず、値が含まれている場合はメソッドに渡します。

前提

  • Python
    • 3.11

対応

辞書型をパラメータに使用します。辞書型で**を使用するとキーワード引数に展開されて使用できます。

class DictDomain:
    @staticmethod
    def action(a: str = "1", b: str = "2", c: str = "3"):
        print(a, b, c)


def test_param_method():
    dict = {"a": "a", "b": "b", "c": None}
    DictDomain.action(**dict)
    # print文の結果
    # a b None

辞書型で値がNoneの時にキーを削除する処理をします。

def test_param_method():
    dict = {"a": "a", "b": "b", "c": None}
    all_key_has_value = {k: v for k, v in dict.items() if v is not None}
    DictDomain.action(**all_key_has_value)
    # print文の結果
    # キーワードに渡されていないので、デフォルトの3が出力される
    # a b 3

ただ私が慣れていないこともあり、非常に読みづらいので必要な項目だけ辞書型に絞ったほうが分かりやすいと思います。

def test_param_method():
    dict = {"c": None}
    all_key_has_value = {k: v for k, v in dict.items() if v is not None}
    DictDomain.action("a"="a", "b"="b", **all_key_has_value)

注意点

辞書型を動的に加工するので静的解析が効きません。具体的には定義していないキーワードを指定していても、静的解析が効かなくなるのでTypoをした場合に気付くタイミングが遅れてしまいます。画像はVSCodeの警告の有無を表現しています。

import pytest

def test_undifined_parameter():
    with pytest.raises(TypeError):
        param = {"d": 1}
        DictDomain.action(**param)
        param2 = {k: v for k, v in param.items() if v is not None}
        DictDomain.action(**param2)

ソースコード

終わりに

Factory_boyを使用してデータのセットアップをしていましたが、NotNullで定義している項目に対してNoneを設定するとValidationErrorが発生します。このエラーを回避しようとしましたがFactory_boy側で回避する方法が見つからなかったため、呼び出し側で対処するようにしました。

テストコードなので次のコードのように単純化しようとしましたが、項目が多かったのと共通化したかったので、今回の方式を取ろうとしています。

if c:
    DictDomain.action("a"="a", "b"="b", "c"=c)
else:
    DictDomain.action("a"="a", "b"="b")

非常に使い道のうすい使い方だと思っていますが、ぜひ使ってみてください。

参考情報

類似情報