python装饰器为什么要双层嵌套函数
PHPz
PHPz 2017-04-18 09:41:45
0
6
545

今天学习了一下python的装饰器,比较难理解的是大家举最简单的装饰例子时都是双层嵌套:

但是单层函数,不也能实现装饰功能吗?python把装饰器设置成双层的目的是什么呢?@到底代表什么运作机制。

PHPz
PHPz

学习是最好的投资!

reply all (6)
刘奇

As mentioned by several experts above, the function of decorator (@grammar) is:

@foo def bar(): ...

is equivalent to:

bar = foo(bar)

Translated into Chinese is:

Use the function name@的 function 當作引數來呼叫@function, 並且賦值給 被@

by
function

Because this action is very similar todecoration (modification, expansion, adjustment, restriction...)originalbar, so it is called decorator:

By definition, a decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.

Although it is said to be a decoration, the executedbar跟原本的bar早已不是同一個人了,foois no longer the same person as the original

. foowill return a brand new object, usually a function, but it is very likely that the returned object is not connected at all. Function is neither:

def foo(func): return None @foo def bar(): ...
foo變成了一個很奇怪的裝飾器, 因為他返還的東西是 NoneIn the above example, , not only is there no decoration, it also destroys the function

Back to the example you gave at the beginning:

def foo(func): print('foo') func() @foo def func_a(): print('func_a') func_a()
foo沒有 return述句, 這代表 foo會返還 None, 你寫的根本是個毀滅器(開玩笑), 你看到的效果只是曇花一現的假象, 那是因為在 @語法發揮作用的那一瞬間, printYour syntax is executed

func_a, 你會發現錯誤被引發了, 因為func_aBut you can try calling

which is not a function at all. Of course, the effect you want to achieve cannot be reused

It is true that decorators do not have to use local functions or nested functions, but we usually let the decorator return a function. I think this is a very important point. After all, we all intuitively think that the decorated function is still a function. Function

There are thousands of decorators, and some can indeed use a single layer of nesting, such as registering functions:

registry = [] def register(func): print('register {}'.format(func)) registry.append(func) return func # 還是應該要 return func
The reason is that this action only needs to be processed once during decoration. You don’t want to register it every time you call the function. All we need is the original function.

But for actions likeprinting logorcalculating time

, etc., we still have to use nesting techniques, because we want to print and calculate every time we call the function. What we need is a new function, this Functions are created by local functions, which will inevitably lead to cascading and nesting. There are also some more complex decorators with parameters that may use more than two levels of nesting

Summary

Whether you want to nest or not depends on the purpose, but be sure to remember to return the function after decorating

Questions I answered

: Python-QA
    迷茫

    Maybe you guys don’t understand what I mean. My idea is quite confusing. My question is why python is designed like this, because at first I thought it was useless to nest two layers of functions. A simple decorator and one layer of functions are enough to print a Log, time, etc., this is not the philosophy of Python. I thought about it for a night and understood it myself. The writing is a bit messy. Friends in need can take a look and marvel at the wonderfulness of this design pattern. The backward reasoning method used is to clarify the basic requirements and then reason backwards to understand why each step is written as such.

    def outer(func): #3.此处关键了,因为我们是倒推,下面的结构已经固定了, def inner(x): #outer(f1)返回给f1的值,必须是一个函数!outer自己也是函数 print('loding') #可以返回自己嘛!但是注意哦,它已经有且必须有一个func参数,来传递原生函数名 func(x) #也就是f1函数名变量的入口,那么他返回给新的f1函数,就会使原生函数多个参数, print('Done') #改变我们最初的目的,新f1与老f1调用方法要无区别,那么咋整 return inner #嵌套一个函数inner,他接收f1参数,外层outer接收函数名f1 def f1(x): #至此装饰器是两层函数嵌套,当f1没有参数时,依然需要双层 print('f1 func',x) #因为必须返回一个函数,返回outer本身,就需要加func参数 @outer #而我们又追求不改变原生调用f1(),他是没有参数的 def f2(x): #所以一个装饰器必须至少双层函数嵌套,第一层传递原生函数名 print('f2 func',x) #第二层执行装饰功能,这设计真是牛逼,逆推一晚上才有点理解。 @outer def f3(x): print('f3 func',x) #2.那么F1要指向一个新函数 #并且这个函数能被F2 F3都指向 f1 = outer(f1) #所以它是一个可以传递函数名变量的函数 #f1 = outer(f1('tings')) #ps:带上参数一起传递,这也是一种可能,但是没有价值, #装饰器使用时每个都要写一遍,其实就已经不是原生方法调用了, #因为要给语法糖@输送'things'参数,不符合我们初衷。 f1('tings1') #1.首先明确我们的根本需求,外部调用方法要完全相同,这也是装饰器的意义。 f2('tings2') f3('tings3')
      Ty80
      1. Decorator happens in定义而不是执行stage.

      2. Decorator functionouter必须返回一个被装饰的函数, 注意它必须返回一个定义, 而不是调用

      The detailed explanation downstairs is very good.

        刘奇

        Many people must have shared this. I have also written a blog before. If the topic is interesting, you can check it out:

        Detailed explanation of Python decorators

          PHPzhong
          @foo def bar()

          Equivalent to bar = foo(bar), just understand this

            PHPzhong

            The second floor is right, the function is already executed when assigning a value to bar.

              Latest Downloads
              More>
              Web Effects
              Website Source Code
              Website Materials
              Front End Template
              About us Disclaimer Sitemap
              php.cn:Public welfare online PHP training,Help PHP learners grow quickly!