オプションのパラメータの値がデフォルト値から来ているのか、それともユーザーが関数呼び出しで明示的に設定したのかを確認する簡単な方法はありますか?
10 に答える
あまり。標準的な方法は、ユーザーが渡すことを期待されないデフォルト値を使用することです。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
ます。
次の関数デコレータ はexplicit_checker
、明示的に指定されたすべてのパラメータのパラメータ名のセットを作成します。結果を追加パラメーター ( explicit_params
) として関数に追加します。'a' in explicit_params
パラメータa
が明示的に指定されているかどうかを確認するだけです。
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)
普遍的に一意の文字列 (UUID など) を使用することがあります。
import uuid
DEFAULT = uuid.uuid4()
def foo(arg=DEFAULT):
if arg is DEFAULT:
# it was not passed in
else:
# it was passed in
このように、ユーザーが試みたとしてもデフォルトを推測することさえできなかったので、 のその値を見るとarg
、それが渡されなかったと確信できます。
私はこのパターンを数回見ました (例: library unittest
、py-flags
、jinja
):
class Default:
def __repr__( self ):
return "DEFAULT"
DEFAULT = Default()
...または同等のワンライナー...:
DEFAULT = type( 'Default', (), { '__repr__': lambda x: 'DEFAULT' } )()
とは異なりDEFAULT = object()
、これは型チェックを支援し、エラーが発生したときに情報を提供します。多くの場合、文字列表現 ( "DEFAULT"
) またはクラス名 ( "Default"
) がエラー メッセージで使用されます。
ボラティリティのコメントに同意します。ただし、次の方法で確認できます。
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
少し変わったアプローチは次のとおりです。
class CheckerFunction(object):
def __init__(self, function, **defaults):
self.function = function
self.defaults = defaults
def __call__(self, **kwargs):
for key in self.defaults:
if(key in kwargs):
if(kwargs[key] == self.defaults[key]):
print 'passed default'
else:
print 'passed different'
else:
print 'not passed'
kwargs[key] = self.defaults[key]
return self.function(**kwargs)
def f(a):
print a
check_f = CheckerFunction(f, a='z')
check_f(a='z')
check_f(a='b')
check_f()
どの出力:
passed default
z
passed different
b
not passed
z
前述したように、これは非常に奇妙ですが、うまく機能します。ただし、これは非常に読みにくく、 ecatmurの提案と同様に、自動的に文書化されません。