1. ホーム
  2. python

[解決済み] オプション機能のパラメータが設定されているかどうかを確認する方法

2022-12-11 15:09:03

質問

Pythonで、オプショナルパラメータの値がデフォルトのものなのか、それともユーザが関数呼び出し時に明示的に設定したものなのかを簡単に確認する方法はありますか?

どのように解決するのですか?

多くの回答は、完全な情報の断片を持っているので、私のお気に入りのパターンですべてをまとめたいと思います。

デフォルト値は mutable

もしデフォルト値がミュータブルオブジェクトであれば、ラッキーです。Pythonのデフォルト引数は、関数が定義されたときに一度だけ評価されるという事実を利用できます(これについては、最後のセクションの回答の最後にもう少し書いてあります)。

これは、デフォルトのミュータブルな値に対して is を使って、それが引数として渡されたのか、あるいは関数やメソッドとして次の例のようにデフォルトで残されたものなのかを簡単に比較できることを意味します。

def f(value={}):
    if value is f.__defaults__[0]:
        print('default')
    else:
        print('passed in the call')

class A:
    def f(self, value={}):
        if value is self.f.__defaults__[0]:
            print('default')
        else:
            print('passed in the call')

不変のデフォルト引数

さて、もしデフォルトが immutable の値であることが予想される場合 (そして、文字列でさえ不変であることを忘れないでください!) 、そのままではこのトリックを利用できないので、少しエレガントではありませんが、まだできることがあります、やはり可変型を利用するのです。 ミュータブル を関数のシグネチャに、そして目的の "real" のデフォルト値を関数本体に記述します。

def f(value={}):
    """
    my function
    :param value: value for my function; default is 1
    """
    if value is f.__defaults__[0]:
        print('default')
        value = 1
    else:
        print('passed in the call')
    # whatever I want to do with the value
    print(value)

特に、本当のデフォルトが None である場合、特におかしく感じます。 None はimmutableなので...やはり関数のデフォルトパラメータとして明示的にmutableを使用し、コード内でNoneに切り換える必要があります。

を使う Default クラスを使用することで、デフォルトを不変にすることができます。

または、@c-z の提案と同様に、python のドキュメントで十分でない場合 :-) 、API をより明確にするために間にオブジェクトを追加することができます。used_proxy_ Defaultクラスのインスタンスは変更可能で、使用したい本当のデフォルト値が含まれます。

class Default:
    def __repr__(self):
        return "Default Value: {} ({})".format(self.value, type(self.value))

    def __init__(self, value):
        self.value = value

def f(default=Default(1)):
    if default is f.__defaults__[0]:
        print('default')
        print(default)
        default = default.value
    else:
        print('passed in the call')
    print("argument is: {}".format(default))

今すぐ

>>> f()
default
Default Value: 1 (<class 'int'>)
argument is: 1

>>> f(2)
passed in the call
argument is: 2

上記は Default(None) .

その他のパターン

上記のパターンが必要以上に醜いのは、すべての print があるためです。それ以外は、私はそれらが簡潔で、十分に再現可能であることがわかります。

を追加するデコレータを書くことができます。 __call__ パターンを追加するデコレータを書くこともできますが、この場合、関数定義自体に奇妙なトリックを使う必要があります。 valuevalue_default を区別する必要があるのなら、あまり利点はないと思いますし、例も書きません :-)

Pythonのデフォルト値としてのMutable型

についてもう少し詳しく #1 python gotcha! について、もう少し詳しく説明します。 のために何が起こるかを見ることができます。 の評価によって起こることがわかります。 をすることで

def testme(default=[]):
    print(id(default))

を実行することができます。 testme() を何度でも実行でき、常に同じデフォルトインスタンスへの参照が表示されます (つまり、基本的にデフォルトは不変です :-) )。

Pythonでは、3つのmutableなインスタンスしかないことを思い出してください。 組み込みの型 : set , list , dict 他のすべてのもの - 文字列でさえも! - は不変です。