Jak mogę znaleźć liczbę argumentów funkcji Pythona?


163

Jak mogę znaleźć liczbę argumentów funkcji Pythona? Muszę wiedzieć, ile ma normalnych argumentów i ile nazwanych argumentów.

Przykład:

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

Ta metoda ma 2 argumenty i 1 nazwany argument.


43
pytanie jest w pełni uzasadnione; gdyby tak nie było (ponieważ zawsze możesz odczytać źródło), nie byłoby żadnego uzasadnienia dla inspectstandardowego modułu biblioteki.
— przepływ

Wiele języków zawiera co najmniej jedną nieuzasadnioną funkcję. inspectModuł posiada wiele innych funkcji, dlatego jest niesprawiedliwe powiedzieć, że cały moduł byłoby nieuzasadnione, jeśli jedna szczególna funkcja w nim było. Co więcej, łatwo jest zobaczyć, jak ta funkcja może być źle wykorzystana. (Zobacz stackoverflow.com/questions/741950 ). To powiedziawszy, jest to przydatna funkcja, szczególnie do pisania dekoratorów i innych funkcji, które działają na funkcję.
— user1612868

Odpowiedzi:


131

Poprzednio zaakceptowana odpowiedź została wycofana z dnia Python 3.0. Zamiast używać inspect.getargspec, powinieneś teraz wybrać Signatureklasę, która go zastąpiła.

Tworzenie podpisu dla funkcji jest łatwe dzięki signaturefunkcji :

from inspect import signature

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

sig = signature(someMethod)

Teraz możesz szybko wyświetlić jego parametry, strużywając go:

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

lub możesz również uzyskać mapowanie nazw atrybutów na obiekty parametrów za pośrednictwem sig.parameters.

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

Dodatkowo, można zadzwonić lenna sig.parameterscelu również zobaczyć liczbę argumentów funkcja ta wymaga:

print(len(params))  # 3

Każdy wpis w paramsmapowaniu jest w rzeczywistości Parameterobiektem, który ma dalsze atrybuty ułatwiające życie. Na przykład pobranie parametru i wyświetlenie jego wartości domyślnej można teraz łatwo wykonać za pomocą:

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

podobnie dla pozostałych obiektów zawartych w parameters.


Jeśli chodzi o 2.xużytkowników Pythona , chociaż inspect.getargspec nie jest przestarzały, język wkrótce będzie :-). SignatureKlasa nie jest dostępny w 2.xserii i nie będzie. Więc nadal musisz pracować inspect.getargspec.

Jeśli chodzi o przejście między Python 2 i 3, jeśli masz kod, który opiera się na interfejsie getargspecw Pythonie 2 i przełączania signaturesię 3to zbyt trudne, to trzeba cenną opcję korzystania inspect.getfullargspec. Oferuje podobny interfejs do getargspec(pojedynczy wywoływalny argument) w celu pobrania argumentów funkcji, jednocześnie obsługując kilka dodatkowych przypadków, które getargspecnie:

from inspect import getfullargspec

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

args = getfullargspec(someMethod)

Podobnie jak w przypadku getargspec,getfullargspec zwraca wartość NamedTuplezawierającą argumenty.

print(args)
FullArgSpec(args=['self', 'arg1', 'kwarg1'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={})

1
Nie ma za co @ GeorgSchölly. Zaskoczyło mnie popularne pytanie, takie jak to, które oferowało rozwiązania, które albo były przestarzałe, albo podstępne (zerkając w co_argcountatrybut).
— Dimitris Fasarakis Hilliard

1
getfullargspecnie jest zaimplementowany w Pythonie 2.x, musisz użyćgetargspec
— Peter Gibson

getargspecnie działa na funkcjach wbudowanych: getargspec(open)daje TypeError: <built-in function open> is not a Python functionZobacz tę odpowiedź dla niektórych pomysłów ...
— starfry

W twoim ostatnim przykładzie, kiedy to robisz print(args), nie defaults=(None,)dostajesz defaults=None.
— Seanny123,

si istnieje sposób na uzyskanie oryginalnej liczby parametrów funkcji, która została udekorowana po dekoracji ..?
— Gulats

117
import inspect
inspect.getargspec(someMethod)

zobacz moduł inspekcji


5
Ogólnie to, czego chcesz, ale to nie działa w przypadku funkcji wbudowanych. Jedynym sposobem, aby dowiedzieć się, jak uzyskać te informacje dla wbudowanych, jest przeanalizowanie ich notki dokumentacyjnej , co jest błędne, ale wykonalne.
— Cerin


Czy istnieje rozwiązanie, które nie jest przestarzałe w Pythonie 3?
— hlin117

1
Jeśli klikniesz link, zobaczysz, że zaleca użycie inspect.signature- docs.python.org/3/library/inspect.html#inspect.signature
— coderforlife

Opublikowałem tutaj inne możliwe podejście do funkcji wbudowanych bez analizowania ciągów dokumentów: stackoverflow.com/questions/48567935/ ...
— HelloWorld

31
someMethod.func_code.co_argcount

lub, jeśli nazwa bieżącej funkcji jest nieokreślona:

import sys

sys._getframe().func_code.co_argcount

4
@elyase, po prostu zrób: dir(someMethod)-> 'func_code'; Idź dalej: dir(someMethod.func_code)-> 'co_argcount'; Możesz użyć wbudowanego, dir()aby określić dostępne metody obiektu.

@elyase Ja też byłem ciekawski, więc znalazłem to docs.python.org/2/library/inspect.html#types-and-members
— rodripf

Aby obsługiwać Python 3:six.get_function_code(someMethod).co_argcount
— noisecapella

8
@noisecapella nie ma potrzeby stosowania zewnętrznego modułu, kiedy możesz po prostu to zrobićsome_method.__code__.co_argcount
— vallentin

1
Ogólnie rzecz biorąc, nie powinieneś zaglądać do wnętrza obiektu funkcji, aby spojrzeć na te rzeczy. co_argcountjest używany wewnętrznie podczas oceny obiektu kodu. Próbuję powiedzieć, że naprawdę nie ma gwarancji, że te atrybuty nie zmienią się z jednej wersji na drugą.
— Dimitris Fasarakis Hilliard

16

inspect.getargspec ()

Uzyskaj nazwy i domyślne wartości argumentów funkcji. Zwracana jest krotka czterech rzeczy: (args, varargs, varkw, defaults). args to lista nazw argumentów (może zawierać listy zagnieżdżone). varargs i varkw to nazwy argumentów * i ** lub None. defaults jest krotką domyślnych wartości argumentów lub None, jeśli nie ma domyślnych argumentów; jeśli ta krotka ma n elementów, odpowiadają one ostatnim n elementom wymienionym w args.

Zmienione w wersji 2.6: zwraca nazwaną krotkę ArgSpec (args, varargs, words, defaults).

Zobacz can-you-list-the-keyword-arguments-a-python-function-takes .


5

Dodając do powyższego, zauważyłem również, że w większości przypadków funkcja help () naprawdę pomaga

Na przykład podaje wszystkie szczegóły dotyczące argumentów, które przyjmuje.

help(<method>)

podaje poniżej

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

Byłoby dobrze, gdyby ludzie zostawili komentarz na temat tego, co jest nie tak z postem, niż kliknięcie przycisku minus.
— Venu Murthy

2
helpfunkcja pokazuje tylko to, co mówi napis. Czy nawet przetestowałeś, czy działa z definicją funkcji w pytaniu?
— 0xc0de

@ 0xc0de - Czy to przetestowałeś? Ponieważ to faktycznie działa. help()wypluwa więcej niż tylko ciąg dokumentów - nawet w przypadku nieudokumentowanego kodu nadal wypisuje argument argspec i informuje, gdzie kod został zdefiniowany. Osoba, która opublikowała oryginalne pytanie, nie była pewna, czy potrzebuje odpowiedzi przyjaznej dla maszyny czy człowieka. Jeśli tylko ma być przyjazny człowiekowi, help()jest całkowicie wystarczający.
— ArtOfWarfare

@ArtOfWarfare wcale nie, ponieważ teraz musiałbyś przeanalizować wszystko help(), co zwraca, i spróbować znaleźć argsi kwargs.
— Vallentin

5

Dobra wiadomość dla osób, które chcą to zrobić w sposób przenośny między Pythonem 2 a Pythonem 3.6+: użyj inspect.getfullargspec() metody. Działa zarówno w Pythonie 2.x, jak i 3.6+

Jak zauważył Jim Fasarakis Hilliard i inni, kiedyś wyglądało to tak:
1. W Pythonie 2.x: użyj inspect.getargspec()
2. W Pythonie 3.x: użyj podpisu, as getargspec()i getfullargspec()zostały uznane za przestarzałe.

Jednak po uruchomieniu Pythona 3.6 (ze względu na popularne zapotrzebowanie?), Rzeczy zmieniły się w kierunku lepszych:

Ze strony dokumentacji Python 3 :

inspect.getfullargspec (func)

Zmieniono w wersji 3.6 : Ta metoda została wcześniej udokumentowana jako przestarzała na korzyść signature()w Pythonie 3.5, ale ta decyzja została cofnięta w celu przywrócenia wyraźnie obsługiwanego standardowego interfejsu dla kodu Python 2/3 z jednego źródła, który migrował ze starszego getargspec()interfejsu API.


3

inspect.getargspec () do Twoich potrzeb

from inspect import getargspec

def func(a, b):
    pass
print len(getargspec(func).args)

1
Witamy w Stack Overflow! Nie odpowiadaj tylko za pomocą kodu źródłowego. Postaraj się przedstawić miły opis tego, jak działa Twoje rozwiązanie. Zobacz: Jak napisać dobrą odpowiedź? . Dzięki
— sɐunıɔ ןɐ qɐp

2

Jak sugerują inne odpowiedzi, getargspecdziała dobrze, o ile pytana rzecz jest w rzeczywistości funkcją. To nie działa na wbudowanej funkcji, takich jak open, lenitd, i rzuci wyjątek w takich przypadkach:

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

Poniższa funkcja (zainspirowana tą odpowiedzią ) przedstawia obejście. Zwraca liczbę argumentów oczekiwaną przez 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

Chodzi o to, aby wyodrębnić specyfikację funkcji z __doc__ciągu. Oczywiście zależy to od formatu wspomnianego ciągu, więc nie jest wytrzymałe!


2

func.__code__.co_argcountdaje liczbę ewentualnych argumentów PRZED *args

func.__kwdefaults__daje dykt argumentów słów kluczowych PO *args

func.__code__.co_kwonlyargcount jest równe len(func.__kwdefaults__)

func.__defaults__podaje wartości opcjonalnych argumentów, które pojawiają się wcześniej *args

Oto prosta ilustracja:

ilustracja

>>> 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

0

W:

import inspect 

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

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

Na zewnątrz:

4


Uwaga: Gdyby xyz nie należało do klasy X i nie zawierało „self”, a tylko „a, b, c”, to wypisałoby 3.

W przypadku Pythona poniżej 3.5 możesz zamienić inspect.getfullargspecgo inspect.getargspecna w powyższym kodzie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.