Как я могу найти количество аргументов функции Python?

163

Как я могу найти количество аргументов функции Python? Мне нужно знать, сколько у него нормальных аргументов и сколько именованных аргументов.

Пример:

def someMethod(self, arg1, kwarg1=None):
    pass

Этот метод имеет 2 аргумента и 1 именованный аргумент.

Георг Шолли
источник
43
вопрос полностью оправдан; если это не так (поскольку вы всегда можете прочитать исходный код), для inspectстандартного модуля библиотеки не было бы никакого оправдания .
поток
Множество языков реализуют хотя бы одну неоправданную функцию. inspectМодуль имеет много других функций, так что это несправедливо сказать , что весь модуль будет неоправданным , если одна конкретная функция в нем была. Более того, легко увидеть, как эта функция может использоваться плохо. (См. Stackoverflow.com/questions/741950 ). Тем не менее, это полезная функция, особенно для написания декораторов и других функций, которые работают с функцией.
user1612868

Ответы:

131

Ранее принятый ответ устарел с Python 3.0. Вместо использования inspect.getargspecвы должны выбрать Signatureкласс, который заменил его.

Создать подпись для функции легко с помощью signatureфункции :

from inspect import signature

def someMethod(self, arg1, kwarg1=None):
    pass

sig = signature(someMethod)

Теперь вы можете быстро просмотреть его параметры, используя strего:

str(sig)  # returns: '(self, arg1, kwarg1=None)'

или вы также можете получить сопоставление имен атрибутов с объектами параметров через sig.parameters.

params = sig.parameters 
print(params['kwarg1']) # prints: kwarg1=20

Кроме того, вы можете позвонить lenна sig.parametersтакже увидеть количество аргументов этой функции необходимо:

print(len(params))  # 3

Каждая запись в paramsотображении на самом деле является Parameterобъектом, который имеет дополнительные атрибуты, облегчающие вашу жизнь. Например, захват параметра и просмотр его значения по умолчанию теперь легко выполняется с помощью:

kwarg1 = params['kwarg1']
kwarg1.default # returns: None

аналогично для остальных объектов, содержащихся в parameters.


Что касается 2.xпользователей Python , хотя inspect.getargspec и не считается устаревшим, язык скоро будет :-). SignatureКласс не доступен в 2.xсерии , и не будет. Так что вам все еще нужно работать inspect.getargspec.

Что касается перехода между Python 2 и 3, если у вас есть код , который опирается на интерфейс getargspecв Python 2 и переход к signatureв 3слишком сложно, у вас есть ценный вариант использования inspect.getfullargspec. Он предлагает интерфейс, похожий на getargspec(один вызываемый аргумент), чтобы получить аргументы функции, а также обрабатывать некоторые дополнительные случаи, которые getargspecэтого не делают:

from inspect import getfullargspec

def someMethod(self, arg1, kwarg1=None):
    pass

args = getfullargspec(someMethod)

Как и getargspec, getfullargspecвозвращает a, NamedTupleкоторый содержит аргументы.

print(args)
FullArgSpec(args=['self', 'arg1', 'kwarg1'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={})
Димитрис Фасаракис Хиллиард
источник
1
Добро пожаловать @ GeorgSchölly. Я был удивлен, что такой популярный вопрос, как этот, предлагал решения, которые либо устарели, либо просто подлый (заглядывал в co_argcountатрибут).
Димитрис Фасаракис Хиллиард
1
getfullargspecне реализован в Python 2.x, вы должны использоватьgetargspec
Питер Гибсон
getargspecне работает со встроенными функциями: getargspec(open)дает TypeError: <built-in function open> is not a Python functionСм. этот ответ для некоторых идей ...
starfry
В вашем последнем примере, когда вы делаете, print(args)вы не получаете, defaults=(None,)вы получаете defaults=None.
Seanny123
si есть способ получить исходное количество параметров для функции, которая была оформлена после оформления ..?
Гулатс
117
import inspect
inspect.getargspec(someMethod)

см. модуль проверки

Йохен Ритцель
источник
5
Как правило, что вы хотите, но это не работает для встроенных функций. Единственный способ узнать, как получить эту информацию для встроенных команд, - это проанализировать их строку документа , что не очень понятно, но выполнимо.
Cerin
5
Это не рекомендуется в Python 3: docs.python.org/3/library/inspect.html#inspect.getargspec
noisecapella
Есть ли решение, которое не рекомендуется в Python 3?
hlin117
1
Если вы перейдете по ссылке, то увидите, что она рекомендует использовать inspect.signature- docs.python.org/3/library/inspect.html#inspect.signature
coderforlife
Я разместил еще один возможный подход для встроенных функций без разбора строки документации здесь: stackoverflow.com/questions/48567935/…
HelloWorld,
31
someMethod.func_code.co_argcount

или, если текущее имя функции не определено:

import sys

sys._getframe().func_code.co_argcount
miaoever
источник
4
@elyase, просто сделай: dir(someMethod)-> 'func_code'; Идти дальше: dir(someMethod.func_code)-> 'co_argcount'; Вы можете использовать встроенный dir()для определения доступных методов объекта.
@elyase Я тоже был в смятении, так что я нашел этот docs.python.org/2/library/inspect.html#types-and-members
rodripf
Для поддержки Python 3:six.get_function_code(someMethod).co_argcount
noisecapella
8
@noisecapella нет необходимости в стороннем модуле, когда вы можете просто это сделатьsome_method.__code__.co_argcount
vallentin
1
В общем, вы не должны заглядывать внутрь объекта функции, чтобы посмотреть на эти вещи. co_argcountиспользуется внутри во время оценки объекта кода. Я пытаюсь сказать, что на самом деле нет никаких гарантий, что эти атрибуты не изменятся от одного выпуска к другому.
Димитрис Фасаракис Хиллиард
16

inspect.getargspec ()

Получить имена и значения по умолчанию аргументов функции. Возвращается кортеж из четырех вещей: (args, varargs, varkw, defaults). args - это список имен аргументов (он может содержать вложенные списки). varargs и varkw - это имена аргументов * и ** или None. значения по умолчанию - это кортеж значений аргументов по умолчанию или None, если аргументов по умолчанию нет; если этот кортеж имеет n элементов, они соответствуют последним n элементам, перечисленным в аргументах.

Изменено в версии 2.6: Возвращает именованный кортеж ArgSpec (args, varargs, ключевые слова, значения по умолчанию).

См. Can-you-list-the-keyword-arguments-a-python-function-receive .

гимель
источник
5

Помимо вышесказанного, я также видел, что в большинстве случаев функция help () действительно помогает

Например, он дает все детали об аргументах, которые он принимает.

help(<method>)

дает ниже

method(self, **kwargs) method of apiclient.discovery.Resource instance
Retrieves a report which is a collection of properties / statistics for a specific customer.

Args:
  date: string, Represents the date in yyyy-mm-dd format for which the data is to be fetched. (required)
  pageToken: string, Token to specify next page.
  parameters: string, Represents the application name, parameter name pairs to fetch in csv as app_name1:param_name1, app_name2:param_name2.

Returns:
  An object of the form:

    { # JSON template for a collection of usage reports.
    "nextPageToken": "A String", # Token for retrieving the next page
    "kind": "admin#reports#usageReports", # Th
Вену Мурти
источник
Для людей было бы хорошо оставить комментарий о том, что не так с сообщением, чем просто нажать на кнопку минус.
Вену Мурти
2
helpФункция показывает только то, что говорит строка документации. Вы даже проверяли, работает ли оно с определением функции в вопросе?
0xc0de
@ 0xc0de - Ты проверял это? Потому что это действительно работает. help()выплевывает больше, чем просто строку документации - даже на недокументированном коде он по-прежнему печатает argspec и сообщает вам, где был определен код. Человек, который разместил оригинальный вопрос, не знал, нужен ли ему ответ, который был бы машинным или дружественным для человека. Если это только нужно, чтобы быть дружественным к человеку, help()это вполне адекватно.
ArtOfWarfare
@ArtOfWarfare совсем нет, так как теперь вам придется анализировать все help()возвращаемые данные и пытаться найти argsи kwargs.
vallentin
5

Хорошие новости для людей, которые хотят сделать это портативным способом между Python 2 и Python 3.6+: используйте inspect.getfullargspec() метод . Работает как в Python 2.x, так и в 3.6+

Как отмечали Джим Фасаракис Хиллиард и другие, раньше это было так:
1. В Python 2.x: использование inspect.getargspec()
2. В Python 3.x: использование подписи, поскольку getargspec()и getfullargspec()устарели.

Однако, начиная с Python 3.6 (по многочисленным просьбам?), Ситуация изменилась к лучшему:

Со страницы документации Python 3 :

inspect.getfullargspec (FUNC)

Изменено в версии 3.6 : этот метод ранее был задокументирован как устаревший в пользу signature()Python 3.5, но это решение было отменено для восстановления явно поддерживаемого стандартного интерфейса для кода Python 2/3 с одним исходным кодом, отходящего от устаревшего getargspec()API.

HAltos
источник
3

inspect.getargspec () для удовлетворения ваших потребностей

from inspect import getargspec

def func(a, b):
    pass
print len(getargspec(func).args)
Eds_k
источник
1
Добро пожаловать в стек переполнения! Пожалуйста, не отвечайте только с исходным кодом. Попробуйте дать хорошее описание того, как работает ваше решение. Смотрите: Как мне написать хороший ответ? , Спасибо
sɐunıɔ ןɐ qɐp
2

Как предполагают другие ответы, getargspecработает хорошо, пока запрашиваемая вещь на самом деле является функцией. Он не работает для встроенных функций, таких как open, lenи т. Д., И выдает исключение в таких случаях:

TypeError: <built-in function open> is not a Python function

Функция ниже (вдохновленная этим ответом ) демонстрирует обходной путь. Возвращает ожидаемое количество аргументов f:

from inspect import isfunction, getargspec
def num_args(f):
  if isfunction(f):
    return len(getargspec(f).args)
  else:
    spec = f.__doc__.split('\n')[0]
    args = spec[spec.find('(')+1:spec.find(')')]
    return args.count(',')+1 if args else 0

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

starfry
источник
2

func.__code__.co_argcountдает ряд каких - либо аргументов ДО *args

func.__kwdefaults__дает вам подсказку ключевых аргументов ПОСЛЕ *args

func.__code__.co_kwonlyargcount равно len(func.__kwdefaults__)

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

Вот простая иллюстрация:

иллюстрация

>>> def a(b, c, d, e, f=1, g=3, h=None, *i, j=2, k=3, **L):
    pass

>>> a.__code__.co_argcount
7
>>> a.__defaults__
(1, 3, None)
>>> len(a.__defaults__)
3
>>> 
>>> 
>>> a.__kwdefaults__
{'j': 2, 'k': 3}
>>> len(a.__kwdefaults__)
2
>>> a.__code__.co_kwonlyargcount
2
Hzzkygcs
источник
0

В:

import inspect 

class X:
    def xyz(self, a, b, c): 
        return 

print(len(inspect.getfullargspec(X.xyz).args))

Вне:

4


Примечание: если xyz не был внутри класса X и не имел «self» и просто «a, b, c», то он напечатал бы 3.

Для python ниже 3.5, вы можете заменить inspect.getfullargspecна inspect.getargspecв коде выше.

Гийом Шевалье
источник