多くの変数を含むより大きなdictから期待される変数を渡すために、Python関数を呼び出す前に、Python関数によって期待される変数をリストすることが可能かどうか疑問に思っています。
ネットを検索しましたが、何も見つかりませんでした。ただし、Pythonインタープリターは期待される変数のリストを表示できるので、スクリプトでそれを行う方法は確かにあるはずですか?
多くの変数を含むより大きなdictから期待される変数を渡すために、Python関数を呼び出す前に、Python関数によって期待される変数をリストすることが可能かどうか疑問に思っています。
ネットを検索しましたが、何も見つかりませんでした。ただし、Pythonインタープリターは期待される変数のリストを表示できるので、スクリプトでそれを行う方法は確かにあるはずですか?
inspect.signature()
またはinspect.getfullargspec()
関数のいずれかを使用できます。
import inspect
argspec = inspect.getfullargspec(somefunction)
signature = inspect.signature(somefunction)
inspect.fullargspec
7つの要素を持つ名前付きタプルを返します。
*args
パラメーターの名前(None
それ以外の場合)**kwargs
パラメーターの名前(None
それ以外の場合)オブジェクトinspect.signature()
を取得すると、上記のデータをより構造化されたオブジェクトのセットとしてモデル化するだけでなく、関数の呼び出しと同じように値をパラメーターにバインドできるリッチオブジェクトが得られます。Signature
どちらが良いかは、ユースケースによって異なります。
デモ:
>>> import inspect
>>> def foo(bar, baz, spam='eggs', *monty, python: "kwonly", spanish=42, **inquisition) -> "return annotation":
... pass
...
>>> inspect.getfullargspec(foo)
FullArgSpec(args=['bar', 'baz', 'spam'], varargs='monty', varkw='inquisition', defaults=('eggs',), kwonlyargs=['python', 'spanish'], kwonlydefaults={'spanish': 42}, annotations={'return': 'return annotation', 'python': 'kwonly'})
>>> signature = inspect.signature(foo)
>>> signature
<Signature (bar, baz, spam='eggs', *monty, python: 'kwonly', spanish=42, **inquisition) -> 'return annotation'>
>>> signature.parameters['python'].kind.description
'keyword-only'
>>> signature.bind('Eric', 'Idle', 'John', python='Cleese')
<BoundArguments (bar='Eric', baz='Idle', spam='John', python='Cleese')>
values
可能なパラメータ値の名前が付けられた辞書がある場合は、マッピングをinspect.signature()
使用して名前を照合します。Signature.parameters
posargs = [
values[param.name]
for param in signature.parameters.values()
if param.kind is Parameter.POSITIONAL_ONLY
]
skip_kinds = {Parameter.POSITIONAL_ONLY, Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD}
kwargs = {
param.name: values[param.name]
for param in signature.parameters.values()
if param.name in values and param.kind not in skip_kinds
}
上記は、位置のみのパラメーターの値のリストと、残りのパラメーター(*args
または**kwargs
パラメーターを除く)の辞書を示しています。
副次的な答えとして、私は今、別のアプローチを使用して、期待する変数を関数に渡します。つまり、すべてを渡します。
つまり、ルートオブジェクト(他のすべてのオブジェクトの親)で変数の一種のグローバル/共有辞書を維持しているということです。例:
shareddict = {'A': 0, 'B':'somestring'}
次に、次のように、このdictを呼び出される他のオブジェクトのメソッドに渡すだけです。
shareddict.update(call_to_func(**shareddict))
ご覧のとおり、shareddictのすべてのキー/値をcall_to_func()のキーワード引数として解凍します。また、返された結果でshareddictを更新します。その理由を以下に示します。
このテクニックを使用すると、このdictから1つまたは複数の変数が必要かどうかを、関数/メソッドで簡単かつ明確に定義できます。
my_method1(A=None, *args, **kwargs):
''' This method only computes on A '''
new_A = Do_some_stuff(A)
return {'A': new_A} # Return the new A in a dictionary to update the shared value of A in the shareddict
my_method2(B=None, *args, **kwargs):
''' This method only computes on B '''
new_B = Do_some_stuff(B)
return {'B': new_B} # Return the new B in a dictionary to update the shareddict
my_method3(A=None, B=None, *args, **kwargs):
''' This method swaps A and B, and then create a new variable C '''
return {'A': B, 'B': A, 'C': 'a_new_variable'} # Here we will update both A and B and create the new variable C
お気づきのように、上記のすべてのメソッドは変数のdictを返します。これにより、shareddictが更新され、他の関数に渡されます。
この手法にはいくつかの利点があります。
json.dumps(finaldict, sort_keys=True)
。素晴らしくて簡単:
import inspect #library to import
def foo(bar, baz, spam='eggs', *monty, **python): pass #example function
argspec = inspect.signature(foo)
print(argspec) #print your output
印刷:(bar、baz、spam ='eggs'、* monty、** python)
クラス内のメソッドでも機能します(非常に便利です!):
class Complex: #example Class
def __init__(self, realpart, imagpart): #method inside Class
... self.r = realpart
... self.i = imagpart
argspec = inspect.signature(Complex)
print(argspec)
プリント:(realpart、imagpart)