2010-09-16 12 views
13

Dada una función:¿Cómo puedo cambiar programáticamente la argspec de una función en un decorador de Python?

def func(f1, kw='default'): 
    pass 
bare_argspec = inspect.getargspec(func) 

@decorator 
def func2(f1, kw='default'): 
    pass 
decorated_argspec = inspect.getargspec(func2) 

¿Cómo puedo crear un decorador de tal manera que bare_argspec == decorated_argspec?

(En cuanto a por qué, el marco que llama a la función decorada hace una inspección argspec para elegir qué pasar, por lo que el decorador tiene que retener el mismo argspec para jugar bien. Cuando planteé esta pregunta en #python, Recibí un largo discurso sobre por qué apesta el marco, que no es lo que estoy buscando, tengo que resolver el problema aquí. Además, también estoy interesado en la respuesta)

+1

SyntaxError: inválido - Creo que quiere decir 'def func (...' –

Respuesta

12

Michele Simionato's decorator module tiene un decorador llamado decorador que conserva la función argspecs.

import inspect 
import decorator 

def func(f1, kw='default'): 
    pass 
bare_argspec = inspect.getargspec(func) 
print(bare_argspec) 
# ArgSpec(args=['f1', 'kw'], varargs=None, keywords=None, defaults=('default',)) 

@decorator.decorator 
def mydecorator(func,*args,**kw): 
    result=func(*args,**kw) 
    return result 

@mydecorator 
def func2(f1, kw='default'): 
    pass 
decorated_argspec = inspect.getargspec(func2) 
print(decorated_argspec) 
# ArgSpec(args=['f1', 'kw'], varargs=None, keywords=None, defaults=('default',)) 

assert(bare_argspec==decorated_argspec) 
0

Son functools.update_wrapper() y/o functools.wraps() lo suficientemente bueno?

+6

Nop, no preservan la argspec. –

2

Ahí está el módulo de decorator:

from decorator import decorator 
@decorator 
def trace(func, *args, **kw): 
    print 'calling', func, 'with', args, kw 
    return func(*args, **kw) 

Eso hace trace un decorador con los mismos argspecs como la función decorada. Ejemplo:

>>> @trace 
... def f(x, y=1, z=2, *args, **kw): 
...  pass 

>>> f(0, 3) 
calling f with (0, 3, 2), {} 

>>> from inspect import getargspec 
>>> print getargspec(f) 
ArgSpec(args=['x', 'y', 'z'], varargs='args', keywords='kw', defaults=(1, 2)) 
Cuestiones relacionadas