闭包函数 装饰器 迭代器
閉包函數
一、什么是閉包
閉包:閉是封閉(函數內部函數),包是包含(該內部函數對外部作用域而非全局作用域的變量的引用)。閉包指的是:函數內部函數對外部作用域而非全局作用域的引用。簡單的說閉包函數就是把變量和函數一起包起來,下次要用直接使用
def outter(x):def inner():print(x)return innerinner = outter(2) # inner # f = innerinner()inner()inner() # 查看閉包的元素 print(F"f.__closure__[0].cell_contents: {f.__closure__[0].cell_contents}")結果:
2
2
2
f.__closure__[0].cell_contents: 2
二、閉包函數的應用
閉包的含義:返回的函數對象,不僅僅是一個函數對象,在該函數外還包裹一層作用域,這使得該函數無論在何處調用,優先先使用自己外層包裹的作用域
應用領域:延遲計算(原來我們是傳參的,現在我們包裹起來)、怕成領域
import requestsdef get(url):response = requests.get(url)print(f"done: {url}")get('https://www.baidu.com') get('https://www.baidu.com') get('https://www.baidu.com')get('https://www.cnblogs.com/linhaifeng') get('https://www.cnblogs.com/linhaifeng') get('https://www.cnblogs.com/linhaifeng')one: https://www.baidu.com
done: https://www.baidu.com
done: https://www.baidu.com
done: https://www.cnblogs.com/linhaifeng
done: https://www.cnblogs.com/linhaifeng
done: https://www.cnblogs.com/linhaifeng
上面的方式是極其復雜的,我們如果使用默認參數也只能解決一個網址,因此我們可以考慮使用閉包的方式。
def func(url):def get_url():r = requests.get(url)r.raise_for_status()r.encoding = r.apparent_encodingprint(f'{url})# print(r.text[:1000])return get_urlget_baidu = func("https://www.baidu.com/")get_baidu() get_baidu()get_taobao = func('https://www.taobao.com/') get_taobao() get_taobao() get_taobao()print(get_taobao.__closure__[0].cell_contents)結果:
url:https://www.baidu.com/
url:https://www.baidu.com/
url:https://www.taobao.com/
url:https://www.taobao.com/
url:https://www.taobao.com/
get_taobao.__closure__[0].cell_contentshttps://www.taobao.com/
裝飾器
一、無參裝飾器
1.1 什么是裝飾器?
裝飾器,器指的是工具,二而程序中的函數就是具備某一功能的工具,所以裝飾器指的是為被裝飾器對象(函數)添加額外功能。因此定義裝飾器就是定義一個函數,只不過該函數的功能是用來為其他函數添加額外的功能
裝飾器本質就是一個函數A,裝飾的對象也是一個函數B,用一個函數A去裝飾一個函數B,
需要注意的是:
裝飾器本身其實就是可以任意調用的對象
被裝飾的對象也可以是任意可調用的對象
def A():"""裝飾器"""passdef B():"""被裝飾的對象"""passB()
1.2 為什么要用裝飾器?
如果我們已經上線了一個項目,我們需要修改某一個方法,但是我們不想修改方法的使用方法,這個時候可以使用裝飾器。因為軟件的維護應該遵循開放封閉原則,即軟件一旦上線運行后,軟件的維護對修改源代碼是封閉的,對擴展功能指的是開放的。
裝飾器的實現必須遵循兩大原則:
裝飾器其實就是在遵循以上兩個原則的前提下為被裝飾對象添加新功能。
1.3 如何使用裝飾器
def index():"""被裝飾的函數"""print('hello, index')index()對上面函數實現:
打印函數運行的時
1.1 改變了函數體代碼,沒改變調用方式
import time def index():start = time.time()print("hello, index")time.sleep(1)end = time.time()print(end - start) index()1.2 沒改變調用方式,也沒改變源碼,但是不通用
import time def index():print("hello, index")start = time.time() index() time.sleep(1) end = time.time()print(end - start)裝飾器
檢測index的運行的時間,但是不能改變index的調用方式,以及index的源碼
def deco(func): # func = 真正的index"""裝飾器函數"""def inner():start = time.time()func() # 真正的index()time.sleep(1)end = time.time()print(ent - start)return innerdef index():"""被裝飾的函數"""print("hello, index")# 實現index函數調用 index = deco(index) # index = inner index() # f1()二、裝飾器語法糖
在被裝飾函數正上方,并且是單獨一行寫上@裝飾器名
def deco(func): # func = 真正的index"""裝飾器函數"""def inner():start = time.time()func() # 真正的index()time.sleep(1)end = time.time()print(ent - start)return innerdef index():"""被裝飾的函數"""print("hello, index") @deco index()三、裝飾器模板
def outter(func):def inner(*args, **kwagrs):res = func(*args, **kwagrs)return resreturn inner def deco(func):"""裝飾器"""def inner(*args, **kwargs): # inner是未來要運行的函數res = func(*args, **kwargs) # func實際調用的函數return resreturn inner@deco def index(x, a=12):"""被裝飾的對象"""print('x:',x,)print("a:", a)print('hello index')return indexres = index() print(res)實現一個用戶登錄裝飾器。
def login(func):def ingfunc(*args, **kwargs):username = input("請輸入用戶名:")userpwd = input("請輸入密碼:")if username == 'randy' and userpwd:print("登錄成功")res = func(*args, **kwargs)else:print('失敗')return resreturn ingfunc@login def shopping():print('shoppoing')shopping()四、三層裝飾器
# 三層裝飾器 def sanceng(engine):def outter(func):def wrapper(*args, **kwargs):# 加功能print(engine)res = func(*args, **kwargs) # func被裝的函數return resreturn wrapperreturn outter@sanceng('file') def shopping()print("shopping") # 判斷賬號密碼來自于哪個地方 #三層裝飾器: 給雙層裝飾器加參數 def auth(engine):def login(func):def inner(*args, **kwargs):# 登錄功能if engine == 'file':username = input('usrename:')pwd = input('pwd:')if username == 'nick' and pwd == '123':print('登錄成功')res = func(*args, **kwargs) # shopping() return reselse:print('登錄失敗')elif engine == 'db':print('賬號密碼來自于數據庫,非法請求')return innerreturn login@auth('db') def shopping():print('shopping')login = auth('db') # login = login shopping = login(shopping) # shopping = inner shopping() # inner() # 疊加多個裝飾器 # 1. 加載順序(outter函數的調用順序):自下而上 # 2. 執行順序(wrapper函數的執行順序):自上而下迭代器
一、迭代器的概念
迭代器即迭代的工具,那什么是迭代呢?
迭代是一個重復的過程,每次重復即一次迭代,并且每次迭代的結果都是下一次迭代的初始值
二、可迭代對象
python中一切皆對象,對于這一切的對象中,但凡有__iter__方法的對象,都是可迭代對象。
基于上一次的結果推出下一次結果
# # 可迭代(具有__iter__方法)對象x = 2 # 不可迭代 # x.__iter__ # SyntaxError: invalid syntaxs = 'randysun' s.__iter__() # str 為可迭代對象lt = [1, 2, 3] lt.__iter__() # list 為可迭代對象dic = {'a': 1, "b": 2} dic.__iter__() # dict 為可迭代對象tup = (1,) tup.__iter__() # tuple 為可迭代對象se = {1, 2, 3} se.__iter__() # 可迭代對象f = open('test.py') f.__iter__() # 可迭代對象def func():pass # 不可迭代對象# 有__iter__()方法的對象都是可迭代對象,然后除了數字類型和函數之外都是可迭代對象可迭代的對象:Python內置str、list、tuple、dict、set、file都是可迭代對象。
s = 'randysun's_iter = s.__iter__() print(s_iter.__next__()) print(s_iter.__next__()) print(s_iter.__next__())特點:
二、迭代器對象
迭代器對象: 具有__iter__以及__next__方法的叫做迭代器對象
s = 'nick' # 可迭代對象,不屬于迭代器對象 s.__iter__() lt = [1, 2, 3] # 可迭代對象,不屬于迭代器對象 dic = {'a': 1, 'b': 2} # 可迭代對象,不屬于迭代器對象 tup = (1,) # 元組只有一個元素必須得加逗號# 可迭代對象,不屬于迭代器對象 se = {1, 2, 3} # 可迭代對象,不屬于迭代器對象 f = open('time.py') # 可迭代對象,迭代器對象# 只有文件是迭代器對象 lt = [1, 2, 3] lt_iter = lt.__iter__() while True:try:print(lt_iter.__next__())except StopIteration:break1
2
3
- 可迭代對象:具有__iter__方法的對象就是可迭代對象,除了數字類型和函數都是可迭代對象
- 可迭代器對象:具有__iter__和__next__方法的都是迭代器對象,只有文件
- 迭代器對象一定是可迭代對象,可迭代對象不一定是可迭代器對象
- for循環 == 迭代循環
- 把lt(可迭代對象/迭代器對象)用__iter__方法轉換成迭代器對象
- 使用__next__取出迭代器里的所有值
- 使用__next__方法取盡迭代器中的所有值,一定會報錯,通過異常捕捉退出while循環
- 解決了不依賴索引取值
- 優缺點
優點:
- 提供一種統一的、不依賴于索引的迭代方式
- 惰性計算,節省內存
- 無法獲取長度(只有在next完畢才知道到底有幾個值)
- 一次性的,只能往后走,不能往前退
轉載于:https://www.cnblogs.com/xiongchao0823/p/11342931.html
總結
以上是生活随笔為你收集整理的闭包函数 装饰器 迭代器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Spring cloud 一步步实现广
- 下一篇: [Spring cloud 一步步实现广