python基礎三_03_閉包_裝飾器_遞歸
導讀:
本文主要記錄自己學習python3基礎中閉包、裝飾器和遞歸的要點知識和例子;僅供自己梳理。搞清楚函數的作用域是理解閉包,裝飾器的前提。
一、閉包
1.什麼是閉包?
(1).閉包的定義
·閉包函數必須有內嵌函數;
·閉包函數必須返回內嵌函數;
·內嵌函數可以引用該嵌套函數上一級namespace(命名空間)中的變量;
(2).閉包的好處
·使代碼變得簡潔;
·提高代碼的拓展性;
2.爲什麼要用閉包?
閉包能夠實現一個封閉的作用域
3.怎麼用閉包?
(1).定義一個閉包函數
對於初學者,就算理解不了閉包的實質,但是這種寫法是固定的,記下來就行。
# 定義
def outer():
# 內嵌函數
def inner():
print('我是inner')
# 返回內嵌函數。python裏變量都是指針,返回函數其實就是返回了一個內存地址
return inner # 是返回函數,不是調用函數,切忌寫成inner()
# 調用
new_Func_Name = outer()
new_Func_Name()
# 這兩步調用的是內嵌函數inner,類似於:outer()()
# print(func)
# <function outer.<locals>.inner at 0x00000209DE974048>
# 可以看到func就是inner,所以func的調用就是inner的調用。func() === inner()
(2).理解閉包
閉包能夠實現一個封閉的作用域,內嵌函數inner可以使用外部函數的變量。說白了,閉包,閉包,閉的就是作用域,變量。
例一:內嵌函數使用外部函數的變量
def outera():
num = 20
def innera(num_in):
print('我是inner,num_in is {}'.format(num_in))
return num + num_in
return innera
funa = outera()
# 調用
print(funa(40))
print(funa(50))
print(funa(1))
怎麼樣?有點明白什麼是閉包了嗎?
例:還可以在進行傳參
def outerb(num):
def innerb(num_in):
print('我是inner,num_in is {}'.format(num_in))
return num + num_in
return innerb
funb = outerb(20)
#
print(funb(2))
例:還可以這樣
def outerc(num):
c = 100
def innerc(num_in):
print('我是inner,num_in is {}'.format(num_in))
return num + num_in + c
return innerc
func = outerc(20)
#
print(func(2))
二、裝飾器
如果理解了閉包,那麼裝飾器就很好理解了,前面說的閉包就是它的前身。
1.裝飾器的定義
裝飾器用來在原有的函數上增添新的代碼需求,裝飾器是程序開發中經常會用到的一個功能。
2.應用場景
當我們已經寫好一個函數時,項目也已經上線了,突然客戶想要增添一個需求,讓這個函數處理的更加細緻,這個就可以用到裝飾器了;
淘寶登錄驗證。在使用淘寶購物,
3.執行順序:
先返回內嵌函數–>有參數直接傳參給內嵌函數–>執行內嵌函數
4.結合典例理解裝飾器
場景:線上代碼如下,在不改變源碼的情況下,要求增添一個新功能,輸出:‘I come from china’。要求分別使用閉包和裝飾器來實現
def func1():
print('this is ydxq')
def func2():
print('this is bjl')
#
func1()
func2()
需求的輸出結果如下:
法一:閉包實現
# 源代碼
def func1():
print('this is ydxq')
# 增加閉包函數
def outer(func):
def inner():
func()
print('I come from china')
return inner
# f1 = outer(func1)
# f1()
# 由於python是動態類型語言,那我們乾脆直接重新賦值一下func1,說白了就是把這個'f1'改成'func1'
func1 = outer(func1)
func1() # 這樣是不是實現了咱們添加功能的需求?秀吧?
法二:裝飾器實現
裝飾器其實就是閉包更秀一點的寫法,叫 ‘@語法糖’,採用裝飾器的寫法,感覺代碼更加整潔。
# 先寫一個閉包
def outer1(func):
def inner1():
func()
print('I come from china')
return inner1
# 然後在原來的函數上面,寫'@+閉包函數名'
@outer1 # 這個意思就是:func1 = outer(func1)
def func1():
print('this is bjl')
# 調用
func1()
可以return
def outer2(func):
def inner2(name):
print(name)
data = func()
print('I come from china')
return data+name
return inner2
@outer2
def func2():
print('func4 this is bjl')
return 'coll '
# 調用
print(func2('ydxq'))
當然,我們也可以傳參
def outer3(func):
def inner3(name):
# name的作用域只有inner3裏面這塊
print(name)
func()
print('I come from china')
return inner3
@outer3 # 這個意思就是:func1 = outer(func1)
def func3():
print('this is bjl')
func3('ydxq')
可以這樣
def outer4(func):
def inner4(name):
# name的作用域只有inner3裏面這塊
print(name)
func(name)
print('I come from china')
return inner4
@outer4 # 這個意思就是:func1 = outer(func1)
def func4(name):
print('func4 this is bjl, {}'.format(name))
func4('YDXQ')
甚至可以這樣
def outer5(func):
def inner5(name,*args,**kwsrgs):
data = func(*args,**kwsrgs)
print('I come from china')
return data + name
return inner5
@outer5 # 這個意思就是:func1 = outer(func1)
def func5(name,*args,**kwsrgs):
print('this is bjl')
print(name,*args,**kwsrgs)
return 'coll'
#func5('WSD')
print(func5('WSD',1,2,3,4,{'a':'1','b':'2','c':'3'}))
三、遞歸函數(不是重點)
1.遞歸函數簡介
(1).函數的內部可以調用其他函數
def func1():
print('func1')
def func2():
print('func2')
# main函數用於控制函數調用順序,約定俗稱的名字還有:run()、work()等
def main():
func2()
func1()
main()
(2).既然在函數當中能夠調用其他函數,那在函數中調用自己可以嗎?可以的
如果一個函數在內部調用自身,這個函數就是遞歸函數,遞歸會形成一個深度循環!
2、示例
例一:階乘
法一:for 循環,廣度循環
num = int(input('>>>'))
result = 1
for i in range(1,num+1):
result *= i
print(result)
法二:while循環,深度循環
i = 1
result = 1
num = int(input('>>>'))
while i < num+1:
result = result * i
i += 1
print(result)
法三:遞歸函數:注意遞歸出口的設置
num = int(input('>>>'))
def test(n):
# 遞歸出口,如果沒有遞歸出口就會造成棧溢出的情況
if n == 1:
return 1
else:
return n * test(n-1)
result = test(num)
print(result)
注意遞歸出口的設置
num = int(input('>>>'))
def test(n):
return n * test(n-1)
result = test(num)
print(result)
例二:斐波那契數列
法一:普通while循環,動態類型語言,序列解包賦值
def feibo(n):
a,b = 0,1
c = []
while n > 0:
c.append(b)
a,b = b,a+b
n -= 1
print(c)
feibo(5)
法二:遞歸函數
n = 5
def feibo(n):
# 兩個條件控制遞歸出口
if n <= 1:
return n
if n == 2:
return 1
return feibo(n - 1) + feibo( n - 2)
res = [feibo(i) for i in range(1,n+1)]
print(res)
解決棧溢出-----尾遞歸
return 後面沒有表達式 就是尾遞歸。但是python目前解決不了,所以不建議使用,知道就行。