python基礎之閉包函式及裝飾器原理分析

2021-08-22 07:16:25 字數 4158 閱讀 7822

一、閉包函式

裝飾器的本質是閉包函式,下面我就先來回顧一下閉包函式。

閉包函式:內部函式包含對外部作用域而非全域性作用域變數的引用,該內部函式稱為閉包函式,也就是說函式內部定義的函式就是閉包函式。

那麼我們直接來看下閉包函式的**:

def func_****():

name = "bug"

def inner():

print(name)

print(inner) # .inner at 0x02b8bcd8>

# 判斷乙個函式是否是閉包函式的做法是在閉包函式的上一級列印這個函式名+__closure__

# 如果列印的結果內部有cell at 這個元素,那麼這個函式就是閉包函式

# inner.__closure__返回的是乙個元組

print(inner.__closure__) # (,)

return inner

f = func_****()

# 執行了函式func,返回了inner,實際上inner是乙個指向了inner()函式位址的變數

# 那麼就相當於執行 f = inner,將f的指向了inner,具備了inner的位址

f()# 那麼實際上再執行f(),實際上是執行的是func函式內部的inner函式

print(f) # .inner at 0x02b8bcd8>

上面是這個閉包函式的**,下面這個是這個**的執行順序,可以清晰的看到執行的過程了。

閉包函式也可以巢狀來使用,只不過是中間多了一層推導過程罷了。

# 閉包函式的巢狀使用

hobby = "nothing"

def func():

name = "****"

def inner():

print(name, hobby)

return inner()

return func

i = f()

i()

閉包函式的應用,可以應用在爬蟲領域,引用他人部落格上的乙個例子,讓我們看看校花這個**。

# 閉包函式的應用

from urllib.request import urlopen

def index():

url = ""

def get():

return urlopen(url).read()

return get

xiaohua = index()

content = xiaohua()

print(content)

二、裝飾器

什麼是裝飾器呢,裝飾器就是乙個函式,是閉包函式的乙個延伸,其本質與閉包函式沒有什麼區別,只不過增加了語法糖@,讓**看起來更流暢。我們使用裝飾器就是想讓程式增加一些擴充套件的功能,但是不能改變原程式**及函式呼叫方式,只能增加,我們先看乙個簡單的裝飾器,不可避免的還是用測試函式時間來舉例吧。

# 裝飾器,檢測函式執行時間

import time

def timer(func):

def inner():

start = time.time()

func() # 引用了外層函式的形參變數

print("the time time_check cost:", time.time() - start)

return inner

@timer # ===>>> time_check = timer(time_check)

def time_check():

print("this is time check function")

time.sleep(10)

time_check()

# 我們從@time這一行可以看到,這跟閉包並沒有什麼區別。

我們從上段**可以知道,只有乙個裝飾器是很簡單的,很容易就看出了多層的執行順序,那麼多個裝飾器裝飾乙個函式呢,讓我們來看看兩個裝飾器裝飾乙個函式吧。

# 多個裝飾器裝飾乙個函式,**一下這樣的執行順序的問題

print("2:in inner1_before")

func() # func:print("3:in inner1_after")

return inner1

print("5:in inner2_before")

print("6:in inner2_after")

return inner2

# 裝飾器裝飾test後將test這個函式名指向了**?

# test = inner2

print("7:this is the function test we use")

test()

上段**是不是看起來很清晰,但是他內部執行時還是有點複雜的,沒關係,來個看一看他的執行順序。

其實我們一般來說用不到這麼複雜的,像我例子中的一般inner上面的列印那段**是不會寫的,我們用裝飾器的目的只是想給函式增加功能,只要在inner內部實現功能就好,如果只是在inner內部定製功能,那麼其執行過程我們可以簡要的概述一下:

到這裡裝飾器基本上就沒什麼問題了,再來看一段有關修改名字的**。

# 帶引數的裝飾器及完善

from functools import wraps

@wraps(func)

def inner(*args, **kwargs):

print("do something before")

ret = func(*args, **kwargs)

print("do something after")

return ret

return inner

def func_para(aim):

print(aim)

return "success"

t = func_para("this is test")

print(t)

# 列印結果

# do something before

# this is test

# do something after

# success

那麼給裝飾器加上裝飾器能夠實現麼,可能實現麼,告訴你,沒得問題,還是看**吧。

# 測試裝飾器的使用記錄

from functools import wraps

def inner(*args, **kwargs):

print("這是最外層裝飾器,測試另乙個裝飾器,之前的動作")

ret = func(*args, **kwargs)

print("這是最外層裝飾器,測試另乙個裝飾器,之後的動作")

return ret

return inner

@wraps(func)

def inner(*args, **kwargs):

print("do something before")

ret = func(*args, **kwargs)

print("do something after")

return ret

return inner

def func_para(aim):

print(aim)

return "success"

t = func_para("this is test")

print(t)

# 這是最外層裝飾器,測試另乙個裝飾器,之前的動作

# do something before

# this is test

# do something after

# 這是最外層裝飾器,測試另乙個裝飾器,之後的動作

# success

好了,今天就這樣吧,自己和自己聊天也挺好玩的,如果你看到了這個文章,那麼就是和你聊天了,哈哈,未謀面的朋友,祝你天天開心。

python基礎 閉包函式

內包函式定義 內部函式包含對外部作用域而非全劇作用域名字的引用,該內部函式稱為閉包函式 函式內部定義的函式稱為內部函式 一 建立乙個閉包 使用外層函式的變數也是閉包 使用外層函式的形參也是閉包 def outter 本質就是 記憶體空間 name zs def inner print name 引用...

python基礎 lambda 冒泡 閉包和裝飾

python使用lambda建立匿名函式 foo 18,9,22,17,24,8,12,27 print list filter lambda x x 3 0,foo print list map lambda x x 2 10,foo import functools,functools def ...

python之函式,閉包

引數 收集引數 引數名 def stu info print info 0 print info 1 print len info print type info stu shanxi 200008966 19 列印結果 shanxi 200008966 3 class tuple 返回值 def ...