una procedimientos por pasar parametros parametro opcionales lista funciones explicacion desempaquetado como argumentos argumento python function methods arguments decorator

procedimientos - pasar una lista como parametro en python



Usar el mismo decorador(con argumentos) con funciones y métodos (4)

Como ya está definiendo un __get__ para usar su decorador en el Método Bound, podría pasar una bandera diciéndole si se está utilizando en un método o función.

class methods(object): def __init__(self, *_methods, called_on_method=False): self.methods = _methods self.called_on_method def __call__(self, func): if self.called_on_method: def inner(self, request, *args, **kwargs): print request return func(request, *args, **kwargs) else: def inner(request, *args, **kwargs): print request return func(request, *args, **kwargs) return inner def __get__(self, obj, type=None): if obj is None: return self new_func = self.func.__get__(obj, type) return self.__class__(new_func, called_on_method=True)

He estado tratando de crear un decorador que se pueda usar con funciones y métodos en Python. Esto por sí solo no es tan difícil, pero cuando se crea un decorador que toma argumentos, parece serlo.

class methods(object): def __init__(self, *_methods): self.methods = _methods def __call__(self, func): def inner(request, *args, **kwargs): print request return func(request, *args, **kwargs) return inner def __get__(self, obj, type=None): if obj is None: return self new_func = self.func.__get__(obj, type) return self.__class__(new_func)

El código anterior ajusta la función / método correctamente, pero en el caso de un método, el argumento de request es la instancia en la que está operando, no el primer argumento que no es propio.

¿Hay alguna forma de saber si el decorador se está aplicando a una función en lugar de a un método, y tratar de acuerdo con esto?


El decorador se aplica siempre a un objeto de función: haga que el decorador print el tipo de argumento y podrá confirmarlo; y generalmente debería devolver también un objeto de función (que ya es un decorador con el apropiado __get__ ! -) aunque hay excepciones a este último.

Es decir, en el código:

class X(object): @deco def f(self): pass

deco(f) se llama dentro del cuerpo de la clase, y, mientras aún está allí, f es una función, no una instancia de un tipo de método. (El método se fabrica y se devuelve en f '' __get__ cuando más tarde se accede a f como un atributo de X o una instancia del mismo).

¿Tal vez puedas explicar mejor el uso de un juguete que quieras para tu decorador, para que podamos ser de más ayuda ...?

Editar : esto va para los decoradores con argumentos, también, es decir,

class X(object): @deco(23) def f(self): pass

entonces es deco(23)(f) que se llama en el cuerpo de la clase, f sigue siendo un objeto función cuando se pasa como el argumento a cualquier decorador invocable deco(23) retorna, y ese invocable aún debe devolver un objeto función (generalmente - con excepciones ;-).


Para ampliar el enfoque __get__ . Esto se puede generalizar en un decorador decorador.

class _MethodDecoratorAdaptor(object): def __init__(self, decorator, func): self.decorator = decorator self.func = func def __call__(self, *args, **kwargs): return self.decorator(self.func)(*args, **kwargs) def __get__(self, instance, owner): return self.decorator(self.func.__get__(instance, owner)) def auto_adapt_to_methods(decorator): """Allows you to use the same decorator on methods and functions, hiding the self argument from the decorator.""" def adapt(func): return _MethodDecoratorAdaptor(decorator, func) return adapt

De esta forma, puedes hacer que tu decorador se adapte automáticamente a las condiciones en las que se usa.

def allowed(*allowed_methods): @auto_adapt_to_methods def wrapper(func): def wrapped(request): if request not in allowed_methods: raise ValueError("Invalid method %s" % request) return func(request) return wrapped return wrapper

Tenga en cuenta que se llama a la función de contenedor en todas las llamadas a funciones, por lo que no debe hacer nada caro allí.

Uso del decorador:

class Foo(object): @allowed(''GET'', ''POST'') def do(self, request): print "Request %s on %s" % (request, self) @allowed(''GET'') def do(request): print "Plain request %s" % request Foo().do(''GET'') # Works Foo().do(''POST'') # Raises


Una solución parcial (específica) que he encontrado se basa en el manejo de excepciones. Estoy intentando crear un decorador para permitir solo ciertos métodos de HttpRequest, pero hacerlo funcionar con ambas funciones que son vistas y métodos que son vistas.

Entonces, esta clase hará lo que yo quiero:

class methods(object): def __init__(self, *_methods): self.methods = _methods def __call__(self, func): @wraps(func) def inner(*args, **kwargs): try: if args[0].method in self.methods: return func(*args, **kwargs) except AttributeError: if args[1].method in self.methods: return func(*args, **kwargs) return HttpResponseMethodNotAllowed(self.methods) return inner

Aquí están los dos casos de uso: decorar una función:

@methods("GET") def view_func(request, *args, **kwargs): pass

y métodos de decoración de una clase:

class ViewContainer(object): # ... @methods("GET", "PUT") def object(self, request, pk, *args, **kwargs): # stuff that needs a reference to self... pass

¿Hay una solución mejor que usar el manejo de excepciones?