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.

Georg Schölly
źródło
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={})
Dimitris Fasarakis Hilliard
źródło
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

Jochen Ritzel
źródło
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
5
Jest to przestarzałe w Pythonie 3: docs.python.org/3/library/inspect.html#inspect.getargspec
noisecapella
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
miaoever
źródło
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 .

gimel
źródło
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
Venu Murthy
źródło
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.

HAltos
źródło
3

inspect.getargspec () do Twoich potrzeb

from inspect import getargspec

def func(a, b):
    pass
print len(getargspec(func).args)
Eds_k
źródło
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!

starfry
źródło
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
Hzzkygcs
źródło
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.

Guillaume Chevalier
źródło