the parameter meaning explicacion determined python introspection kwargs

meaning - python parameter sys argv



Obtener kwargs dentro de la función (6)

Si tengo una función de python así:

def some_func(arg1, arg2, arg3=1, arg4=2):

¿Hay una manera de determinar qué argumentos se pasaron por palabra clave desde dentro de la función?

EDITAR

Para aquellos que preguntan por qué necesito esto, no tengo una razón real, surgió en una conversación y la curiosidad me venció.


¿Hay una manera de determinar qué argumentos se pasaron por palabra clave desde dentro de la función?

Al tratar de evaluar los valores predeterminados de los parámetros de palabras clave, sí, hay opciones:

Código

Opción 1 - locals()

def f(a, b=1, c="1"): print(locals()) f(0) # {''c'': ''1'', ''b'': 1, ''a'': 0}

Opción 2 - Sugerencias de tipo parcial *

def g(a, b:int=1, c:float="1"): pass keys = g.__annotations__ values = g.__defaults__ dict(zip(keys, values)) # {''b'': 1, ''c'': ''1''}

Opción 3 - Consejos de tipo completo *

def h(a:float, b:int=1, c:str="1") -> int: return 0 keys = reversed(list(filter(lambda x: x != "return", h.__annotations__))) values = reversed(h.__defaults__) {k: v for k, v in zip(keys, values) if k != "return"} # {''c'': ''1'', ''b'': 1}

Nota: Ninguna de estas opciones es particularmente Pythonic, pero demuestran potencial.

Detalles

  1. locals() depende de la llamada a la función. Los resultados deben ser valores predeterminados, pero cambian con los valores pasados ​​a la llamada, por ejemplo, f(0) frente a f(0 2, 3)
  2. Las sugerencias de tipo "parciales" significan que solo los parámetros de palabras clave están anotados. Agregar cualquier otra anotación no funcionará con este enfoque ingenuo.
  3. Las sugerencias de tipo "completas" o completas pueden incluir otros parámetros. Realizamos una iteración hacia atrás para evitar comprimir valores con parámetros posicionales opcionales. Como una anotación de "return" es opcional, la filtramos durante la iteración.

* Estas opciones dependen de las sugerencias de tipo y la preservación del orden de inserción de claves (Python 3.6+). Solo dan los valores predeterminados y no cambian con los valores de llamada de función. Las sugerencias de tipo son opcionales ahora mismo en Python, y por lo tanto deben usarse con precaución en el código de producción.

Sugerencia

Solo usaría los últimos métodos para depurar o inspeccionar rápidamente la firma de una función. De hecho, dados los argumentos de solo palabras clave, se puede usar inspect.getargspec() para capturar el kwonlydefaults .

def f(a, *, b=1, c="1"): pass spec = inspect.getfullargspec(f) spec # FullArgSpec(args=[''a''], varargs=None, varkw=None, defaults=None, # kwonlyargs=[''b'', ''c''], kwonlydefaults={''b'': 1, ''c'': ''1''}, # annotations={}) spec.kwonlydefaults # {''b'': 1, ''c'': ''1''}

De lo contrario, combine algunas técnicas con los atributos args y defaults de FullArgSpec :

def get_keywords(func): """Return a dict of (reversed) keyword arguments from a function.""" spec = inspect.getfullargspec(func) keys = reversed(spec.args) values = reversed(spec.defaults) return {k: v for k, v in zip(keys, values)} get_keywords(f) # {''c'': ''1'', ''b'': 1}


¿Desea saber si arg3 era 1 porque se pasó desde afuera o porque era un valor predeterminado? No, no hay forma de hacer esto, que yo sepa. La razón principal, sospecho, es que no hay necesidad de tal conocimiento. Lo que normalmente se hace es lo siguiente:

>>> def func(a, b=None): if b is None: # here we know that function was called as: # func(''spam'') or func(''spam'', None) or func(''spam'', b=None) or func(a=''spam'', b=None) b = 42


Aquí está mi solución a través de decoradores:

def showargs(function): def inner(*args, **kwargs): return function((args, kwargs), *args, **kwargs) return inner @showargs def some_func(info, arg1, arg2, arg3=1, arg4=2): print arg1,arg2,arg3,arg4 return info In [226]: some_func(1,2,3, arg4=4) 1 2 3 4 Out[226]: ((1, 2, 3), {''arg4'': 4})

Puede haber una manera de limpiar esto aún más, pero esto me parece mínimamente intrusivo y no requiere ningún cambio en el código de llamada.

Edición: para probar realmente si los argumentos en particular fueron pasados ​​por palabra clave, entonces haga algo como lo siguiente dentro de some_func:

args, kwargs = info if ''arg4'' in kwargs: print "arg4 passed as keyword argument"

Descargo de responsabilidad: probablemente debería considerar si realmente le importa cómo se aprobaron los argumentos. Todo este enfoque puede ser innecesario.


No, no hay forma de hacerlo en el código Python con esta firma; si necesita esta información, debe cambiar la firma de la función.

Si observa la API de Python C, verá que la forma en que se pasan los argumentos a una función de Python normal es siempre como una tupla más un dictado, es decir, la forma en que es un reflejo directo de una firma de *args, **kwargs . Esa tupla y el dictado se analizan en argumentos posicionales específicos y los que están nombrados en la firma a pesar de que se pasaron por su nombre, y el *a y **kw , si están presentes, solo toman el "desbordamiento" de ese análisis, si cualquiera: solo en este punto el código Python obtiene el control, y para entonces la información que está solicitando ( cómo se aprobaron los distintos argumentos) ya no está disponible.

Por lo tanto, para obtener la información que solicitó, cambie la firma a *a, **kw y realice su propio análisis / validación: esto va "del huevo a la tortilla", es decir, una cierta cantidad de trabajo pero ciertamente factible. mientras que lo que estás buscando sería "de la tortilla al huevo" ... simplemente no es posible ;-).


Solo hazlo así:

def some_func ( arg1, arg2, arg3=None, arg4=None ): if arg3 is None: arg3 = 1 # default value if arg4 is None: arg4 = 2 # default value # do something

De esa manera puede ver cuándo se configuró algo y también puede trabajar con estructuras predeterminadas más complejas (como listas) sin tener que enfrentar problemas como estos:

>>> def test( arg=[] ): arg.append( 1 ) print( arg ) >>> test() [1] >>> test() [1, 1]


Vas a tener que redefinir tu función:

def some_func(*args, **kwargs):

y haz el mariscal tú mismo. No hay manera de distinguir la diferencia entre paso por posición, paso por palabra clave y valor predeterminado.