我阅读了一段非常干净的http://mrcoles.com/blog/3-decorator-examples-and-awesome-python/代码,但是它初始化的方式让我很困惑。我看到这个类装饰器接受了“object”,但是当它运行init时,它把view_func扔到了自己身上。view_func
除了init之外没有在任何地方声明,如果它子类化了object,它怎么知道view_func
是它正在装饰的整个函数,而那个请求是HTTP请求?
from functools import wraps
class my_decorator(object):
def __init__(self, view_func):
self.view_func = view_func
wraps(view_func)(self)
def __call__(self, request, *args, **kwargs):
# maybe do something before the view_func call
response = self.view_func(request, *args, **kwargs)
# maybe do something after the view_func call
return response
# how to use it...
def foo(request): return HttpResponse('...')
foo = my_decorator(foo)
# or...
@my_decorator
def foo(request): return HttpResponse('...')
它确实有效,我只是不知道它到底是如何工作的。在我的logger.py
:
class log_decorator(object):
logpath = "/home/me/logs"
def __init__(self, func):
self.func = func
wraps(func)(self)
def __call__(self, *args, **kwargs):
this_path = "{}/{}".format(logpath, self.func.__name__)
ret = self.func(*args, **kwargs)
open(this_path, 'w').close()
if ret:
with open(this_path, 'a') as myfile:
myfile.write("Arguments were: {}, {}\n".format(args, kwargs))
for line in ret:
l = str(line)
myfile.write(l)
myfile.write('\n')
myfile.close()
return ret
科尔先生基于类的风格帮助我将任何函数的最新输出写入日志记录器中以该函数命名的文件,只需
@log_decorator
def smash_lines(lines):
我的确切问题是,如果这个类是扩展对象并且不需要这些参数,那么它如何知道view_func
和request是什么?基于类的装饰器如何初始化它们自己?谢谢
1条答案
按热度按时间z31licg01#
我不太清楚是什么让您感到困惑,但是由于涉及到Python的一些魔力,所以一步一步的解释似乎是合适的:
my_decorator
是一个类,因此my_decorator(foo)
不是一个简单的方法调用,而是对象创建(如果你想完全正确的话,它也是一个方法调用,即对类my_decorator
的__call__()
方法的调用)。my_decorator(foo)
调用my_decorator.__init__()
,my_decorator.__init__()
将函数foo
填充到这个新对象内的self.view_func
中。例如
你会得到
foo
回来的。1.需要注意的最重要的事情可能是装饰器返回一个对象。
这意味着
用
my_decorator(foo)
的返回值替换原始的foo()
,my_decorator(foo)
是我们刚刚创建的my_decorator
对象,因此在这一行之后,foo
是my_decorator
类型的对象,原始的foo()
作为foo.view_func()
填充在该对象中。1.由于
my_decorator
也通过覆盖__call__()
方法来模拟函数调用,因此任何类似于foo(request, ...)
的调用操作都将调用my_decorator.__call__()
,因此__call__()
基本上取代了foo()
视图函数。