Mat*_*kel 14 python methods arguments function decorator
我一直在尝试创建一个可以在python中与函数和方法一起使用的装饰器.它本身就不那么难,但是当创建一个带参数的装饰器时,它似乎就是这样.
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)
Run Code Online (Sandbox Code Playgroud)
上面的代码正确地包装了函数/方法,但是在方法的情况下,request参数是它正在操作的实例,而不是第一个非自身参数.
有没有办法判断装饰器是否应用于函数而不是方法,并相应地处理?
Ant*_*sma 17
扩展__get__方法.这可以推广到装饰器装饰器中.
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
Run Code Online (Sandbox Code Playgroud)
通过这种方式,您可以让装饰器自动适应其使用的条件.
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
Run Code Online (Sandbox Code Playgroud)
请注意,所有函数调用都会调用包装函数,所以不要在那里做任何昂贵的事情.
装饰者的用法:
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
Run Code Online (Sandbox Code Playgroud)
装饰器总是应用于一个函数对象 - 让装饰器print具有其参数的类型,你将能够确认它; 它通常应该返回一个函数对象(它已经是一个具有正确的装饰器__get__! - )虽然后者有例外.
即,在代码中:
class X(object):
@deco
def f(self): pass
Run Code Online (Sandbox Code Playgroud)
deco(f)在类体内调用,当你还在那里时,它f是一个函数,而不是方法类型的实例.(该方法是制造和返回f的__get__时后f,作为的属性访问X或其实例).
也许你可以更好地解释你想要装饰的玩具,所以我们可以提供更多帮助......?
编辑:这也适用于带有参数的装饰器,即
class X(object):
@deco(23)
def f(self): pass
Run Code Online (Sandbox Code Playgroud)
那么它是deco(23)(f)在类体中调用的,f当作为参数传递给任何可调用的deco(23)返回时仍然是一个函数对象,并且该可调用的仍然应该返回一个函数对象(通常 - 有例外;-).
由于您已经定义了__get__在绑定方法上使用装饰器的方法,因此可以传递一个标志,告诉它是否在方法或函数上使用它。
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)
Run Code Online (Sandbox Code Playgroud)