今天学习了一下python的装饰器,比较难理解的是大家举最简单的装饰例子时都是双层嵌套:
但是单层函数,不也能实现装饰功能吗?python把装饰器设置成双层的目的是什么呢?@到底代表什么运作机制。
学习是最好的投资!
如同上面好幾位大大所說, 裝飾器 (@語法) 的作用:
@foo def bar(): ...
等價於:
bar = foo(bar)
翻成中文就是:
利用被 @ 的 function 當作引數來呼叫 @ function, 並且賦值給 被 @ function 的函數名稱
@
因為這個動作很像是 裝飾(修改, 擴增, 調整, 限制...) 原本的 bar, 所以被叫做 裝飾器:
bar
By definition, a decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.
雖然說是裝飾, 但執行完的bar 跟原本的 bar 早已不是同一個人了, foo 跟原本的
foo
def foo(func): return None @foo def bar(): ...
None
def foo(func): print('foo') func() @foo def func_a(): print('func_a') func_a()
return
print
func_a, 你會發現錯誤被引發了, 因為 func_a但是你大可以試著調用
func_a
registry = [] def register(func): print('register {}'.format(func)) registry.append(func) return func # 還是應該要 return func
但是像打印log 或是計算時間
我回答過的問題
可能各位大神沒明白我的意思,我的想法比較鑽牛角尖,我的問題是python為什麼這麼設計,因為開始我覺得嵌套兩層函數沒有用處,一個簡單的裝飾器,一層函數足以能打印個log,time啥的呀,這不是python的哲學,想了一晚上,自己理解點,寫的比較亂,有需要的朋友可以看看吧,驚嘆於這種設計模式的精彩絕倫。使用的逆推法,也就是明確根本需求,然後倒著推理,每一步為什麼這麼寫。
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')
裝飾器發生在定义而不是执行階段.
定义
执行
裝飾器函數outer必须返回一个被装饰的函数, 注意它必须返回一个定义, 而不是调用
outer
被装饰的函数
调用
樓下講的詳細, 很不錯.
這個應該很多人都分享過了,我之前也寫過一篇博客,題主有意思的話可以查看一下:
Python 裝飾器詳解
@foo def bar()
等價於 bar = foo(bar),理解這就好了
二樓說的對,在給bar賦值的時候就已經執行函數了。
如同上面好幾位大大所說, 裝飾器 (@語法) 的作用:
等價於:
翻成中文就是:
因為這個動作很像是 裝飾(修改, 擴增, 調整, 限制...) 原本的
bar
, 所以被叫做 裝飾器:雖然說是裝飾, 但執行完的
早已不是同一個人了,bar
跟原本的bar
早已不是同一個人了,foo
跟原本的foo
會返回一個全新的對象, 通常是一個function, 但很有可能返回的東西根本連function 都不是:foo
變成了一個很奇怪的裝飾器, 因為他返還的東西是None
在上面的例子中, , 不但沒有裝飾, 還毀滅了 functionfoo
沒有return
述句, 這代表foo
會返還None
, 你寫的根本是個毀滅器(開玩笑), 你看到的效果只是曇花一現的假象, 那是因為在@
語法發揮作用的那一瞬間,print
你的 語法被執行了func_a
, 你會發現錯誤被引發了, 因為func_a
但是你大可以試著調用但是像打印log 或是計算時間
等等的行為, 我們還是得用嵌套的手法, 因為我們每次調用function 都想要打印和計算, 我們需要的是一個新的function, 這個function 就靠local function 製造出來, 那必然會產生層疊和嵌套, 還有一些比較複雜的帶參數的裝飾器, 可能會使用到超過兩層嵌套我回答過的問題
: Python-QA🎜可能各位大神沒明白我的意思,我的想法比較鑽牛角尖,我的問題是python為什麼這麼設計,因為開始我覺得嵌套兩層函數沒有用處,一個簡單的裝飾器,一層函數足以能打印個log,time啥的呀,這不是python的哲學,想了一晚上,自己理解點,寫的比較亂,有需要的朋友可以看看吧,驚嘆於這種設計模式的精彩絕倫。使用的逆推法,也就是明確根本需求,然後倒著推理,每一步為什麼這麼寫。
裝飾器發生在
定义
而不是执行
階段.裝飾器函數
outer
必须返回一个被装饰的函数
, 注意它必须返回一个定义
, 而不是调用
樓下講的詳細, 很不錯.
這個應該很多人都分享過了,我之前也寫過一篇博客,題主有意思的話可以查看一下:
Python 裝飾器詳解
等價於 bar = foo(bar),理解這就好了
二樓說的對,在給bar賦值的時候就已經執行函數了。