2013-02-07 8 views
42

オプションパラメータの値がデフォルト値から来ているかどうかをチェックする簡単な方法はありますか?Python:オプションの関数パラメータが設定されているかどうかをチェックする方法

+2

なぜ重要ですか? – Volatility

+9

私はその機能をチェックしたいからです:) – Matthias

+0

デフォルトとして 'None'を使い、それをチェックしてください。実際にこのテストを設定できる場合は、ユーザーがデフォルトの動作を呼び出す値を明示的に渡す可能性も除外します。 –

答えて

32

標準的な方法は、ユーザが渡すことが予想されないデフォルト値を使用することである。 objectインスタンス:それは、ユーザが合格したい値として意味をなさない場合

DEFAULT = object() 
def foo(param=DEFAULT): 
    if param is DEFAULT: 
     ... 

通常あなただけの、デフォルト値としてNoneを使用することができます。

代替kwargsを使用することです:

def foo(**kwargs): 
    if 'param' in kwargs: 
     param = kwargs['param'] 
    else: 
     ... 

しかしこれは過度に冗長であり、そのドキュメントが自動的にparamパラメータは含まれませんとして使用するあなたの機能をより困難にします。

+0

ありがとう、私はなしのチェックに固執すると思います。 – Matthias

+4

私はまた、これが必要な箇所にはEllipsis組み込み関数を使用し、Noneは有効な入力とみなされています。これは基本的に最初の例と同じです。 – GrandOpener

2

私はボラティリティのコメントに同意します。しかし、あなたは次のようにチェックすることができ:

def function(arg1,...,**optional): 
    if 'optional_arg' in optional: 
     # user has set 'optional_arg' 
    else: 
     # user has not set 'optional_arg' 
     optional['optional_arg'] = optional_arg_default_value # set default 
+0

私はオプションのパラメータは 'def func(optional = value)'のようなものであると信じています。** kwargsではありません –

+0

これは解釈に多少のものです。引数のデフォルト値とキーワード引数の実際の違いは何ですか?それらはどちらも同じ構文 "keyword = value"を使用して表現されます。 – isedev

+0

オプションパラメータと '** kwargs'の目的が少し違うので私は同意しません。 P.S.何も問題はありません-1 :)あなたのための私-1は偶然でした:) –

0

は少し気まぐれなアプローチは、次のようになります。出力

passed default 
z 
passed different 
b 
not passed 
z 

を今、この、私が述べたように、かなり気まぐれですしかし、それは仕事をします。しかし、これは全く読めず、ecatmursuggestionと同様に自動的には文書化されません。

+1

'check_f( 'z')'の振る舞いを含めることもできます。 –

+0

@ MichaelJ.Barber良い点。あなたは* argsでいくつかの "魔法"を行わなければなりません。しかし、私の要点は可能だが、デフォルト値が受け渡されるかどうかは今は悪い設計である。 – dmg

7

次の関数デコレータexplicit_checkerは、明示的に指定されたすべてのパラメータのパラメータ名のセットを作成します。結果を追加パラメータ(explicit_params)として関数に追加します。パラメータaが明示的に指定されているかどうかを確認するには、'a' in explicit_paramsを実行してください。

def explicit_checker(f): 
    varnames = f.func_code.co_varnames 
    def wrapper(*a, **kw): 
     kw['explicit_params'] = set(list(varnames[:len(a)]) + kw.keys()) 
     return f(*a, **kw) 
    return wrapper 

@explicit_checker 
def my_function(a, b=0, c=1, explicit_params=None): 
    print a, b, c, explicit_params 
    if 'b' in explicit_params: 
     pass # Do whatever you want 


my_function(1) 
my_function(1, 0) 
my_function(1, c=1) 
4

時にはユニバーサルユニークな文字列(UUIDなど)を使用します。彼らはので、私は、私はargのためにその値を参照するとき、それは渡されなかったことを非常に確信することができしようとした場合

import uuid 
DEFAULT = uuid.uuid4() 
def foo(arg=DEFAULT): 
    if arg is DEFAULT: 
    # it was not passed in 
    else: 
    # it was passed in 

この方法では、どのユーザーでもデフォルトを推測することができませんでした。

+0

これはちょっとハックですが、簡潔で効果的なものです... – F1Rumors

+0

Pythonオブジェクトは参照であり、 'uuid4()'の代わりに 'object()'を使うことができます - それは依然としてユニークな_instance_です。小切手 –

0

私はこれを見てきましたパターン数回(例えばライブラリunittestpy-flagsjinja):

class Default: 
    def __repr__(self): 
     return "DEFAULT" 

DEFAULT = Default() 

...または同等のワンライナー...:

DEFAULT = type('Default',(), { '__repr__': lambda x: 'DEFAULT' })() 

DEFAULT = object()とは異なり、これは型チェックを支援し、エラーが発生したときに情報を提供します。エラーメッセージに文字列表現("DEFAULT")またはクラス名("Default")が頻繁に使用されます。

関連する問題