今天学习了一下python的装饰器,比较难理解的是大家举最简单的装饰例子时都是双层嵌套:
但是单层函数,不也能实现装饰功能吗?python把装饰器设置成双层的目的是什么呢?@到底代表什么运作机制。
今天学习了一下python的装饰器,比较难理解的是大家举最简单的装饰例子时都是双层嵌套:
但是单层函数,不也能实现装饰功能吗?python把装饰器设置成双层的目的是什么呢?@到底代表什么运作机制。
可能各位大神没明白我的意思,我的想法比较钻牛角尖,我的问题是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')
首先你的代码没有跑通:你写的无法打印出你的结果,原因是调用关系没有理清楚,你这个是很好的一个教案
def foo(func):
def wrapper():
print("name:xxx")
return func()
return wrapper()
def func_a():
print("func\_a:xxx")
foo(func_a) ##################
这样写才能打印出你的结果,你要把return wrapper() 和return wrapper 搞清楚。一个返回的是对象,一个返回的函数。
def foo(func):
def wrapper():
print("name:xxx")
return func()
return wrapper # 没有括号###############是返回的一个函数
def func_a():
print("func_a:xxx")
foo(func_a)()
重点在这里,这个装饰器如你所说还是和你单层的号无区别
改写下函数:
def foo(func):
def wrapper(newStr): 重点的重点来了!!!!!!!!!!!!!!!!
print(newStr)
return func()
return wrapper # 没有括号###############是返回的一个函数
def func_a():
print("func_a:xxx")
foo(func_a)("i9080808")
这个装饰器强大了吧,可以随便给你的房子加任何不同的东西了吧
i9080808
func_a:xxx
1 回答9.5k 阅读✓ 已解决
2 回答5.1k 阅读✓ 已解决
2 回答3.5k 阅读✓ 已解决
3 回答4.4k 阅读
2 回答2.4k 阅读✓ 已解决
2 回答1.5k 阅读✓ 已解决
1 回答2.8k 阅读✓ 已解决
如同上面好幾位大大所說, 裝飾器 (@語法) 的作用:
等價於:
翻成中文就是:
因為這個動作很像是 裝飾(修改, 擴增, 調整, 限制...) 原本的
bar
, 所以被叫做 裝飾器:雖然說是裝飾, 但執行完的
bar
跟原本的bar
早已不是同一個人了,foo
會返回一個全新的對象, 通常是一個 function, 但很有可能返回的東西根本連 function 都不是:在上面的例子中,
foo
變成了一個很奇怪的裝飾器, 因為他返還的東西是None
, 不但沒有裝飾, 還毀滅了 function回到你一開始舉的例子:
你的
foo
沒有return
述句, 這代表foo
會返還None
, 你寫的根本是個毀滅器(開玩笑), 你看到的效果只是曇花一現的假象, 那是因為在@
語法發揮作用的那一瞬間,print
語法被執行了但是你大可以試著調用
func_a
, 你會發現錯誤被引發了, 因為func_a
根本不是一個 function, 當然你想要達到的效果也無法復用裝飾器的確不一定要使用 local function 或是嵌套式的函數, 但是我們通常都會讓裝飾器返還一個 function, 我覺得這是很重要的一點, 畢竟我們都會直覺認為被裝飾過的函數還是個函數
裝飾器的樣貌千千萬萬種, 有的的確使用單層嵌套就可以了, 比如說註冊函數:
原因是這個動作只需要在裝飾的時候處理一次即可, 你不會想要每次調用函數都註冊一次, 我們需要的只是原來的 function.
但是像 打印 log 或是 計算時間 等等的行爲, 我們還是得用嵌套的手法, 因為我們每次調用 function 都想要打印和計算, 我們需要的是一個新的 function, 這個 function 就靠 local function 製造出來, 那必然會產生層疊和嵌套, 還有一些比較複雜的帶參數的裝飾器, 可能會使用到超過兩層嵌套
小結
要不要嵌套要看目的, 但務必記得裝飾後返回函數
我回答過的問題: Python-QA