11

多くの変数を含むより大きなdictから期待される変数を渡すために、Python関数を呼び出す前に、Python関数によって期待される変数をリストすることが可能かどうか疑問に思っています。

ネットを検索しましたが、何も見つかりませんでした。ただし、Pythonインタープリターは期待される変数のリストを表示できるので、スクリプトでそれを行う方法は確かにあるはずですか?

4

3 に答える 3

16

inspect.signature()またはinspect.getfullargspec()関数のいずれかを使用できます。

import inspect

argspec = inspect.getfullargspec(somefunction)
signature = inspect.signature(somefunction)

inspect.fullargspec7つの要素を持つ名前付きタプルを返します。

  • 引数名のリスト
  • 定義されている場合は、catchall*argsパラメーターの名前(Noneそれ以外の場合)
  • 定義されている場合は、catchall**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パラメーターを除く)の辞書を示しています。

于 2013-03-26T13:49:07.833 に答える
2

副次的な答えとして、私は今、別のアプローチを使用して、期待する変数を関数に渡します。つまり、すべてを渡します。

つまり、ルートオブジェクト(他のすべてのオブジェクトの親)で変数の一種のグローバル/共有辞書を維持しているということです。例:

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が更新され、他の関数に渡されます。

この手法にはいくつかの利点があります。

  • 実装は非常に簡単です
  • グローバル変数を使用せずに変数の共有リストを維持するためのエレガントな方法
  • 関数とメソッドは、それらが期待するものを定義に明確に示します(ただし、もちろん1つの注意点は、必須変数でさえ、Noneなどのデフォルト値を持つキーワード引数として設定する必要があることです。これは通常、変数がオプションであることを意味しますが、ここではそうではありません
  • メソッドは継承可能でオーバーロード可能です
  • 同じshareddictが渡されるため、メモリフットプリントが低くなります
  • 子関数/メソッドは、子に渡される引数を定義するルート(トップダウン)ではなく、必要なもの(ボトムアップ)を定義します。
  • 変数の作成/更新が非常に簡単
  • オプションで、たとえばを使用して、これらすべての変数をファイルにダンプするのは非常に簡単ですjson.dumps(finaldict, sort_keys=True)
于 2013-08-08T00:08:27.633 に答える
1

素晴らしくて簡単:

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)

于 2020-05-23T11:58:59.547 に答える