299

与えられた Python 関数:

def a_method(arg1, arg2):
    pass

引数の数と名前を抽出するにはどうすればよいですか。つまり、 への参照があることを考えると、が を返すようにしfuncたいのです。func.[something]("arg1", "arg2")

これの使用シナリオは、デコレーターがあり、実際の関数にキーとして表示されるのと同じ順序でメソッド引数を使用したいということです。"a,b"つまり、私が呼び出したときにデコレータはどのように表示されますa_method("a", "b")か?

4

17 に答える 17

429

モジュールを見てみましょうinspect。これにより、さまざまなコード オブジェクト プロパティが検査されます。

>>> inspect.getfullargspec(a_method)
(['arg1', 'arg2'], None, None, None)

その他の結果は、*args 変数と **kwargs 変数の名前、および提供されるデフォルトです。すなわち。

>>> def foo(a, b, c=4, *arglist, **keywords): pass
>>> inspect.getfullargspec(foo)
(['a', 'b', 'c'], 'arglist', 'keywords', (4,))

Python の特定の実装では、一部の callable が introspectable でない場合があることに注意してください。たとえば、CPython では、C で定義された一部の組み込み関数は、引数に関するメタデータを提供しません。その結果、組み込み関数でValueError使用すると、 が得られます。inspect.getfullargspec()

Python 3.3 以降inspect.signature()、呼び出し可能オブジェクトの呼び出し署名を表示するために使用できます。

>>> inspect.signature(foo)
<Signature (a, b, c=4, *arglist, **keywords)>
于 2008-10-20T14:52:19.863 に答える
102

CPython では、引数の数は

a_method.func_code.co_argcount

そして彼らの名前は

a_method.func_code.co_varnames

これらは CPython の実装の詳細であるため、IronPython や Jython などの Python の他の実装では機能しない可能性があります。

「パススルー」引数を許可する移植可能な方法の 1 つは、署名を使用して関数を定義することfunc(*args, **kwargs)です。これは、外側の API レイヤーが多くのキーワード引数を下位レベルの API に渡すmatplotlibなどでよく使用されます。

于 2008-10-20T14:24:48.593 に答える
28

Python 3 のバージョンは次のとおりです。

def _get_args_dict(fn, args, kwargs):
    args_names = fn.__code__.co_varnames[:fn.__code__.co_argcount]
    return {**dict(zip(args_names, args)), **kwargs}

このメソッドは、args と kwargs の両方を含む辞書を返します。

于 2016-11-01T15:45:21.897 に答える
24

デコレータ メソッドでは、元のメソッドの引数を次のようにリストできます。

import inspect, itertools 

def my_decorator():

        def decorator(f):

            def wrapper(*args, **kwargs):

                # if you want arguments names as a list:
                args_name = inspect.getargspec(f)[0]
                print(args_name)

                # if you want names and values as a dictionary:
                args_dict = dict(itertools.izip(args_name, args))
                print(args_dict)

                # if you want values as a list:
                args_values = args_dict.values()
                print(args_values)

が重要な場合は**kwargs、少し複雑になります。

        def wrapper(*args, **kwargs):

            args_name = list(OrderedDict.fromkeys(inspect.getargspec(f)[0] + kwargs.keys()))
            args_dict = OrderedDict(list(itertools.izip(args_name, args)) + list(kwargs.iteritems()))
            args_values = args_dict.values()

例:

@my_decorator()
def my_function(x, y, z=3):
    pass


my_function(1, y=2, z=3, w=0)
# prints:
# ['x', 'y', 'z', 'w']
# {'y': 2, 'x': 1, 'z': 3, 'w': 0}
# [1, 2, 3, 0]
于 2013-05-14T11:36:45.127 に答える
17

あなたが探しているのはローカルメソッドだと思います-


In [6]: def test(a, b):print locals()
   ...: 

In [7]: test(1,2)              
{'a': 1, 'b': 2}
于 2010-06-07T16:37:20.100 に答える
14

これは、デコレータを使用して、あなたが望むものに役立つと思うものです。

class LogWrappedFunction(object):
    def __init__(self, function):
        self.function = function

    def logAndCall(self, *arguments, **namedArguments):
        print "Calling %s with arguments %s and named arguments %s" %\
                      (self.function.func_name, arguments, namedArguments)
        self.function.__call__(*arguments, **namedArguments)

def logwrap(function):
    return LogWrappedFunction(function).logAndCall

@logwrap
def doSomething(spam, eggs, foo, bar):
    print "Doing something totally awesome with %s and %s." % (spam, eggs)


doSomething("beans","rice", foo="wiggity", bar="wack")

実行すると、次の出力が得られます。

C:\scripts>python decoratorExample.py
Calling doSomething with arguments ('beans', 'rice') and named arguments {'foo':
 'wiggity', 'bar': 'wack'}
Doing something totally awesome with beans and rice.
于 2008-10-21T00:02:19.207 に答える
2

ブライアンの答えの更新:

Python 3 の関数にキーワードのみの引数がある場合は、次を使用する必要がありますinspect.getfullargspec

def yay(a, b=10, *, c=20, d=30):
    pass
inspect.getfullargspec(yay)

これが得られます:

FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=(10,), kwonlyargs=['c', 'd'], kwonlydefaults={'c': 20, 'd': 30}, annotations={})
于 2017-03-22T10:45:19.623 に答える