简体   繁体   English

编写自定义 python 装饰器,以及它们如何初始化的魔力

[英]writing custom python decorators, and the magic of how they init

I am reading a very clean piece of code at http://mrcoles.com/blog/3-decorator-examples-and-awesome-python/ , but the way it initializes confuses me.我正在http://mrcoles.com/blog/3-decorator-examples-and-awesome-python/阅读一段非常干净的代码,但它的初始化方式让我感到困惑。 I see this class decorator taking 'object', but when it runs init, it throws view_func into itself.我看到这个类装饰器采用“对象”,但是当它运行 init 时,它会将 view_func 抛出到自身中。 With view_func not declared anywhere except in init, if it subclasses object, how did it know that view_func was the entire function it's decorating, and that request is the HTTP request?除了在 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('...')

It definitely works, I'm just lost on how it's working exactly.它肯定的作品,我只是失去了它是如何工作的准确。 In my logger.py:在我的 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

Mr. Cole's class based style helps me write the recent output of any function to a file in loggers named after the function with just Cole 先生的基于类的风格帮助我将任何函数的最近输出写入以函数命名的记录器中的文件中

@log_decorator
    def smash_lines(lines):

My exact question would then be how does this class know what view_func and request is, if it is extending object and doesn't require these params?我的确切问题是这个类如何知道 view_func 和 request 是什么,如果它是扩展对象并且不需要这些参数? How do class based decorators initialize themselves?基于类的装饰器如何初始化自己? Thank you谢谢

I'm not quite sure what gets you confused here, but since there is some Python magic involved, a step-by-step explantion seems to be in order:我不太确定是什么让您在这里感到困惑,但是由于涉及到一些 Python 魔法,因此似乎需要逐步解释:

  1. my_decorator is a class. my_decorator是一个类。 my_decorator(foo) is thus not a simple method call but object creation (which, if you want to be totally correct is also a method call, namely to the __call__() method of the class my_decorator ). my_decorator(foo)不是一个简单的方法调用,而是对象创建(如果你想完全正确,它也是一个方法调用,即my_decorator类的__call__()方法)。 Thus type(my_decorator(foo)) == my_decorator .因此type(my_decorator(foo)) == my_decorator
  2. my_decorator(foo) calls my_decorator.__init__() which stuffs away the function foo into self.view_func inside this new object. my_decorator(foo)调用my_decorator.__init__()其远离充塞函数fooself.view_func此新的对象的内部。

For example例如

decorated = my_decorator(foo)
print(foo.view_func)

you will get foo back.你会得到foo回来。

  1. Most important thing to note is probably that the decorator returns an object.要注意的最重要的事情可能是装饰器返回一个对象。

This means that这意味着

@my_decorator
def foo(...):
   pass

replaces the original foo() by the return value from my_decorator(foo) which is the my_decorator object we just created.将原始foo()替换为my_decorator(foo)的返回值, my_decorator(foo)我们刚刚创建的my_decorator对象。 Hence after this line, foo is an object of type my_decorator with the original foo() stuffed inside that object as foo.view_func() .因此,在这一行之后, foo是一个my_decorator类型的对象,原始foo()作为foo.view_func()填充在该对象中。

  1. Since my_decorator also emulates function calls by overriding the __call__() method, any call-like operation like foo(request, ...) gets to call my_decorator.__call__() , instead.由于my_decorator还通过覆盖__call__()方法来模拟函数调用,因此任何类似调用的操作,如foo(request, ...)都可以调用my_decorator.__call__() So __call__() essentially replaced your foo() view function.所以__call__()基本上取代了你的foo()视图函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM