我正在http://mrcoles.com/blog/3-decorator-examples-and-awesome-python/阅读一段非常简洁的代码,但它初始化的方式让我感到困惑。我看到这个类装饰器采用'对象',但是当它运行init时,它会将view_func抛入其自身。除了在init中之外没有声明view_func,如果它是子类对象,它是如何知道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
先生。 Cole的基于类的样式帮助我将任何函数的最近输出写入以该函数命名的记录器中的文件,只需
@log_decorator
def smash_lines(lines):
我的确切问题是这个类如何知道view_func和request是什么,如果它是扩展对象而不需要这些参数?基于类的装饰器如何初始化自己?谢谢
答案 0 :(得分:2)
我不太确定是什么让你感到困惑,但由于涉及到一些Python魔法,所以逐步解释似乎是有序的:
my_decorator
是一个班级。因此my_decorator(foo)
不是一个简单的方法调用,而是对象创建(如果你想完全正确的话,也是一个方法调用,即类__call__()
的{{1}}方法)。因此my_decorator
。type(my_decorator(foo)) == my_decorator
调用my_decorator(foo)
,将my_decorator.__init__()
函数填充到此新对象中的foo
内。例如
self.view_func
你会得到decorated = my_decorator(foo)
print foo.view_func
。
这意味着
foo
将原始@my_decorator
def foo(...):
pass
替换为foo()
的返回值,my_decorator(foo)
是我们刚创建的my_decorator
对象。因此,在此行之后,foo
是my_decorator
类型的对象,其中原始foo()
填充在该对象内foo.view_func()
。
my_decorator
也会通过覆盖__call__()
方法来模拟函数调用,因此任何类似调用的操作(如foo(request, ...)
)都会调用my_decorator.__call__()
。因此__call__()
基本上取代了您的foo()
视图功能。