Вопрос:

Получение имен параметров метода в Python

python decorator introspection

93739 просмотра

11 ответа

16806 Репутация автора

Учитывая функцию Python:

def aMethod(arg1, arg2):
    pass

Как я могу извлечь число и имена аргументов. Т.е., учитывая, что у меня есть ссылка на func, я хочу func. [Something] to return ("arg1", "arg2").

Сценарий использования для этого состоит в том, что у меня есть декоратор, и я хочу использовать аргументы метода в том же порядке, который они отображают для фактической функции в качестве ключа. Т.е., как бы выглядел декоратор, напечатанный «a, b», когда я вызываю aMethod («a», «b»)?

Автор: Staale Источник Размещён: 20.10.2008 02:22

Ответы (11)


90 плюса

26995 Репутация автора

В CPython количество аргументов

aMethod.func_code.co_argcount

и их имена находятся в начале

aMethod.func_code.co_varnames

Это детали реализации CPython, поэтому это, вероятно, не работает в других реализациях Python, таких как IronPython и Jython.

Один переносимый способ допускать «сквозные» аргументы - это определить вашу функцию подписи func(*args, **kwargs). Это много используется, например, matplotlib, где внешний интерфейс API передает множество аргументов ключевых слов API нижнего уровня.

Автор: Jouni K. Seppänen Размещён: 20.10.2008 02:24

296 плюса

87503 Репутация автора

Решение

Взгляните на модуль проверки - это позволит вам проверить различные свойства объекта кода.

>>> inspect.getargspec(aMethod)
(['arg1', 'arg2'], None, None, None)

Другими результатами являются имена переменных * args и ** kwargs, а также значения по умолчанию. то есть.

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

Обратите внимание, что некоторые вызовы не могут быть интроспективными в некоторых реализациях Python. Например, в CPython некоторые встроенные функции, определенные в C, не содержат метаданных об их аргументах. В результате вы получите ValueErrorв случае, если вы используете inspect.getargspec()встроенную функцию.

Начиная с Python 3.3, вы также можете использовать index.signature () , чтобы знать подпись вызова вызываемого объекта:

>>> inspect.signature(foo)
<Signature (a, b, c=4, *arglist, **keywords)>
Автор: Brian Размещён: 20.10.2008 02:52

13 плюса

358 Репутация автора

Вот что я думаю, будет работать на то, что вы хотите, используя декоратор.

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.
Автор: hlzr Размещён: 21.10.2008 12:02

10 плюса

1980 Репутация автора

Я думаю, что вы ищете метод местных жителей -


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

In [7]: test(1,2)              
{'a': 1, 'b': 2}
Автор: Damian Размещён: 07.06.2010 04:37

21 плюса

1696 Репутация автора

В методе декоратора вы можете перечислить аргументы исходного метода следующим образом:

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]
Автор: Mehdi Behrooz Размещён: 14.05.2013 11:36

4 плюса

2795 Репутация автора

Версия 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.

Автор: argaen Размещён: 01.11.2016 03:45

-1 плюса

3292 Репутация автора

Как насчет dir()и vars()сейчас?

Кажется, именно то, что просят просто супер ...

Должен вызываться из области действия.

Но будьте осторожны, что он вернет все локальные переменные, поэтому обязательно сделайте это в самом начале функции, если это необходимо.

Также обратите внимание, что, как указано в комментариях, это не позволяет делать это за пределами сферы действия. Так что не совсем сценарий OP, но по-прежнему соответствует названию вопроса. Отсюда мой ответ.

Автор: JeromeJ Размещён: 07.01.2017 09:34

1 плюс

13 Репутация автора

Обновление для ответа Брайана :

Если функция в 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={})
Автор: user1981531 Размещён: 22.03.2017 10:45

2 плюса

2526 Репутация автора

Возвращает список имен аргументов, обрабатывает частичные и регулярные функции:

def get_func_args(f):
    if hasattr(f, 'args'):
        return f.args
    else:
        return list(inspect.signature(f).parameters)
Автор: lovesh Размещён: 30.05.2017 11:52

5 плюса

586 Репутация автора

Python 3.5+:

Устаревшее предупреждение: inspect.getargspec () устарело, используйте функцию inspect.signature () вместо

Так ранее:

func_args = inspect.getargspec(function).args

Сейчас:

func_args = list(inspect.signature(function).parameters.keys())

Тестировать:

'arg' in list(inspect.signature(function).parameters.keys())

Учитывая, что у нас есть функция 'function', которая принимает аргумент 'arg', это будет оцениваться как True, иначе как False.

Пример из консоли Python:

Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 07:18:10) [MSC v.1900 32 bit (Intel)] on win32
>>> import inspect
>>> 'iterable' in list(inspect.signature(sum).parameters.keys())
True
Автор: Peter Majko Размещён: 26.07.2017 04:10

2 плюса

81 Репутация автора

В Python 3. + с Signatureобъектом под рукой, простой способ получить сопоставление между именами аргументов в значениях, использует метод Signature bind()!

Например, вот декоратор для печати такой карты:

import inspect

def decorator(f):
    def wrapper(*args, **kwargs):
        bound_args = inspect.signature(f).bind(*args, **kwargs)
        bound_args.apply_defaults()
        print(dict(bound_args.arguments))

        return f(*args, **kwargs)

    return wrapper

@decorator
def foo(x, y, param_with_default="bars", **kwargs):
    pass

foo(1, 2, extra="baz")
# This will print: {'kwargs': {'extra': 'baz'}, 'param_with_default': 'bars', 'y': 2, 'x': 1}
Автор: Kfir Eisner Размещён: 20.08.2017 12:09
Вопросы из категории :
32x32