2011-07-05 12 views
5

? Para un decorador que estoy escribiendo me gustaría manipular un parámetro con nombre específico de una función. Considere el siguiente decorador:¿Cómo puedo tratar los argumentos posicionales como argumentos de palabra clave en Python 2

def square_param(param): 
    def func_decorator(func): 
     def func_caller(*args,**kwargs): 
      kwargs[param] = kwargs[param] * kwargs[param] 
      return func(*args,**kwargs) 
    return func_caller 
return func_decorator 

aplicados en la siguiente función:

@square_param('dividend') 
def quotient(divisor=1,dividend=0): 
    return dividend/divisor 

Esto funcionará si los dividendos se denomina como un argumento de palabra clave, por ejemplo:

>>> quotient(dividend=2) 
4 

Sin embargo, cuando se administra como un argumento posicional esto fracasará.

>>> quotient(3,4) 
TypeError: quotient() got multiple values for keyword argument 'dividend' 

con Python 3 que podía resolver esto forzando el parámetro a always given as a keyword:

@square_param('dividend') 
def quotient(divisor=1,*,dividend=0): 
    return dividend/divisor 

pero me gustaría apoyar a Python 2 y también me gustaría poner como pocas restricciones sobre la función .

¿Hay alguna manera de corregir este comportamiento en mi decorador?

+3

Inspeccione el módulo de inspeccionar. Puede tener lo que necesita para esto. Eche un vistazo a getargspec. – Dirk

Respuesta

3

En primer lugar, su decorador square_param no funciona porque no devuelve las funciones. Tiene que ser:

def square_param(param): 
    def func_decorator(func): 
     def func_caller(*args,**kwargs): 
      kwargs[param] = kwargs[param] * kwargs[param] 
      return func(*args,**kwargs) 
     return func_caller 
    return func_decorator 

Ahora me tomó @ consejo de Dirk y se veía en el módulo inspect. Puede hacerlo comprobando primero si el parámetro es uno de los argumentos posicionales de la función, y segundo si se ha especificado ese argumento posicional, y luego modificando esa posición del argumento. También debe asegurarse de modificar solo kwargs si el parámetro se proporcionó como argumento de palabra clave.

import inspect 

def square_param(param): 
    def func_decorator(func): 
     def func_caller(*args,**kwargs): 
      funparams = inspect.getargspec(func).args 
      if param in funparams: 
       i = funparams.index(param) 
       if len(args) > i: 
        args = list(args) # Make mutable 
        args[i] = args[i] * args[i] 
      if param in kwargs: 
       kwargs[param] = kwargs[param] * kwargs[param] 
      return func(*args,**kwargs) 
     return func_caller 
    return func_decorator 
+0

¡Gracias, esto es exactamente lo que estaba buscando! Sobre el regreso de las funciones, ese fue de hecho un pequeño error estúpido hecho en este ejemplo. –

2

incluso sin utilizar Inspect podemos obtener la función params

>>> func = lambda x, y, args: (x, y, {}) 
>>> func.func_code.co_argcount 
3 
>>> func.func_code.co_varnames 
('x', 'y', 'args') 
+0

Gracias! ¿Podría quizás agregar un enlace donde estén documentados los miembros de func_code? No puedo encontrar eso. –

+0

¡De nada! "func_code es el objeto de código que representa el cuerpo de la función compilada". Puede consultar la sección "Tipos que se pueden llamar" en [enlace] (http://docs.python.org/reference/datamodel.html) para obtener más detalles. – Yajushi

Cuestiones relacionadas