¿Cómo puedo encontrar el número de argumentos de una función de Python?

163

¿Cómo puedo encontrar el número de argumentos de una función de Python? Necesito saber cuántos argumentos normales tiene y cuántos argumentos nombrados.

Ejemplo:

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

Este método tiene 2 argumentos y 1 argumento con nombre.

Georg Schölly
fuente
43
la pregunta está totalmente justificada; Si no fuera así (ya que siempre puede leer la fuente), no habría ninguna justificación para el inspectmódulo de biblioteca estándar.
flujo
Muchos idiomas implementan al menos una característica injustificada. El inspectmódulo tiene muchas otras características, por lo que es injusto decir que todo el módulo no estaría justificado si una función en particular lo fuera. Además, es fácil ver cómo esta característica podría usarse mal. (Consulte stackoverflow.com/questions/741950 ). Dicho esto, es una característica útil, especialmente para escribir decoradores y otras funciones que funcionan en función.
user1612868

Respuestas:

131

La respuesta previamente aceptada ha quedado en desuso a partir de Python 3.0. En lugar de usar inspect.getargspec, ahora debe optar por la Signatureclase que la reemplazó.

Crear una firma para la función es fácil a través de la signaturefunción :

from inspect import signature

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

sig = signature(someMethod)

Ahora, puede ver sus parámetros rápidamente al strhacerlo:

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

o también puede obtener una asignación de nombres de atributos a objetos de parámetros mediante sig.parameters.

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

Además, puede llamar lena sig.parametersver también el número de argumentos Esta función requiere:

print(len(params))  # 3

Cada entrada en el paramsmapeo es en realidad un Parameterobjeto que tiene atributos adicionales que te hacen la vida más fácil. Por ejemplo, tomar un parámetro y ver su valor predeterminado ahora se realiza fácilmente con:

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

de manera similar para el resto de los objetos contenidos en parameters.


En cuanto a los 2.xusuarios de Python , aunque inspect.getargspec no está en desuso, el idioma pronto será :-). La Signatureclase no está disponible en la 2.xserie y no lo estará. Así que aún necesitas trabajar con ellos inspect.getargspec.

En cuanto a la transición entre Python 2 y 3, si tiene código que se basa en la interfaz de getargspecPython 2 y el cambio a signatureen 3que es demasiado difícil, usted tiene la opción valiosa de utilizar inspect.getfullargspec. Ofrece una interfaz similar a getargspec(un único argumento invocable) para obtener los argumentos de una función y al mismo tiempo manejar algunos casos adicionales que getargspecno:

from inspect import getfullargspec

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

args = getfullargspec(someMethod)

Al igual que con getargspec, getfullargspecdevuelve un NamedTupleque contiene los argumentos.

print(args)
FullArgSpec(args=['self', 'arg1', 'kwarg1'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={})
Dimitris Fasarakis Hilliard
fuente
1
De nada @ GeorgSchölly. Me sorprendió que una pregunta popular como esta ofreciera soluciones que fueron desaprobadas o que se disimularon (asomándose en el co_argcountatributo)
Dimitris Fasarakis Hilliard
1
getfullargspecno está implementado en Python 2.x, debe usarlogetargspec
Peter Gibson
getargspecno funciona en funciones incorporadas: getargspec(open)da TypeError: <built-in function open> is not a Python functionVer esta respuesta para algunas ideas ...
starfry
En tu último ejemplo, cuando lo print(args)haces no obtienes lo defaults=(None,)que obtienes defaults=None.
Seanny123
si hay una manera de obtener el recuento de parámetros original para una función que se ha decorado después de la decoración ...
Gulats
117
import inspect
inspect.getargspec(someMethod)

ver el módulo de inspección

Jochen Ritzel
fuente
55
Generalmente lo que desea, pero esto no funciona para las funciones integradas. La única forma de saber cómo obtener esta información para los componentes integrados es analizar su cadena de documentos , que es fugosa pero factible.
Cerin
55
Esto está en desuso en Python 3: docs.python.org/3/library/inspect.html#inspect.getargspec
noisecapella
¿Hay una solución que no esté en desuso en Python 3?
hlin117
1
Si sigue el enlace, verá que recomienda usar inspect.signature- docs.python.org/3/library/inspect.html#inspect.signature
coderforlife
Publiqué otro posible enfoque para las funciones integradas sin analizar la cadena de documentación aquí: stackoverflow.com/questions/48567935/…
HelloWorld
31
someMethod.func_code.co_argcount

o, si el nombre de la función actual es indeterminado:

import sys

sys._getframe().func_code.co_argcount
miaoever
fuente
44
@elyase, solo haz: dir(someMethod)-> 'func_code'; Ir más allá: dir(someMethod.func_code)-> 'co_argcount'; Puede usar el incorporado dir()para determinar los métodos disponibles de un objeto.
@elyase Yo también era curioso, así que encontré esto docs.python.org/2/library/inspect.html#types-and-members
rodripf el
Para admitir Python 3:six.get_function_code(someMethod).co_argcount
noisecapella
8
@noisecapella no necesita un módulo de terceros, cuando simplemente puede hacerlosome_method.__code__.co_argcount
vallentin
1
En general, no deberías mirar dentro del objeto de función para mirar estas cosas. co_argcountse usa internamente durante la evaluación del objeto de código. Lo que estoy tratando de decir es que realmente no hay garantías de que estos atributos no cambien de una versión a otra.
Dimitris Fasarakis Hilliard
16

inspect.getargspec ()

Obtenga los nombres y los valores predeterminados de los argumentos de una función. Se devuelve una tupla de cuatro cosas: (args, varargs, varkw, valores predeterminados). args es una lista de nombres de argumentos (puede contener listas anidadas). varargs y varkw son los nombres de los argumentos * y ** o Ninguno. valores predeterminados es una tupla de valores de argumento predeterminados o Ninguno si no hay argumentos predeterminados; si esta tupla tiene n elementos, corresponden a los últimos n elementos listados en args.

Modificado en la versión 2.6: Devuelve una tupla ArgSpec con nombre (args, varargs, palabras clave, valores predeterminados).

Ver can-you-list-the-keyword-argumentos-a-python-function-recibir .

gimel
fuente
5

Además de lo anterior, también he visto que la mayoría de las veces la función help () realmente ayuda

Por ejemplo, da todos los detalles sobre los argumentos que toma.

help(<method>)

da lo siguiente

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
fuente
Sería bueno para las personas dejar un comentario sobre lo que está mal en una publicación que simplemente hacer clic en el botón menos.
Venu Murthy
2
helpLa función solo muestra lo que dice la cadena de documentación. ¿Has probado si funciona con la definición de función en la pregunta?
0xc0de
@ 0xc0de - ¿Lo has probado? Porque realmente funciona. help()escupe más que solo la cadena de documentación: incluso en el código no documentado, todavía imprime la especificación args y le dice dónde se definió el código. La persona que publicó la pregunta original no tenía claro si necesitaban una respuesta que fuera amigable con las máquinas o los humanos. Si solo necesita ser amigable con los humanos, help()es perfectamente adecuado.
ArtOfWarfare
@ArtOfWarfare en absoluto, ya que ahora tendrías que analizar lo que sea que help()regrese e intentar encontrar el argsy kwargs.
vallentin
5

Buenas noticias para las personas que desean hacer esto de forma portátil entre Python 2 y Python 3.6+: use inspect.getfullargspec() método. Funciona tanto en Python 2.xy 3.6+

Como Jim Fasarakis Hilliard y otros han señalado, que solía ser la siguiente manera:
1. En Python 2.x: Uso inspect.getargspec()
2. En Python 3.x: el uso de la firma, como getargspec()y getfullargspec()estaban en desuso.

Sin embargo, comenzando Python 3.6 (¿por demanda popular?), Las cosas han cambiado hacia mejores:

Desde la página de documentación de Python 3 :

inspect.getfullargspec (func)

Modificado en la versión 3.6 : este método se documentó anteriormente como obsoleto a favor de signature()Python 3.5, pero esa decisión se ha revertido para restaurar una interfaz estándar claramente compatible para el código Python 2/3 de origen único que migra fuera de la getargspec()API heredada .

HAltos
fuente
3

inspect.getargspec () para satisfacer sus necesidades

from inspect import getargspec

def func(a, b):
    pass
print len(getargspec(func).args)
Eds_k
fuente
1
¡Bienvenido a Stack Overflow! Por favor no responda solo con el código fuente. Intente proporcionar una buena descripción sobre cómo funciona su solución. Ver: ¿Cómo escribo una buena respuesta? . Gracias
sɐunıɔ ןɐ qɐp
2

Como sugieren otras respuestas, getargspecfunciona bien siempre que lo que se esté consultando sea en realidad una función. No funciona para una función de funciones tales como open, len, etc, y se producirá una excepción en estos casos:

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

La siguiente función (inspirada en esta respuesta ) muestra una solución alternativa. Devuelve el número de args esperado por 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

La idea es analizar la especificación de la función fuera de la __doc__cadena. Obviamente, esto se basa en el formato de dicha cadena, por lo que no es robusto.

starfry
fuente
2

func.__code__.co_argcountle da el número de los argumentos ANTES *args

func.__kwdefaults__le da un resumen de los argumentos de palabras clave DESPUÉS *args

func.__code__.co_kwonlyargcount es igual a len(func.__kwdefaults__)

func.__defaults__le da los valores de argumentos opcionales que aparecen antes *args

Aquí está la ilustración simple:

la ilustracion

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

En:

import inspect 

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

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

Fuera:

4 4


Nota: Si xyz no estuviera dentro de la clase X y no tuviera "self" y solo "a, b, c", entonces habría impreso 3.

Para pitón por debajo de 3,5, es posible que desee reemplazar inspect.getfullargspecpor inspect.getargspecel código de seguridad.

Guillaume Chevalier
fuente