日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

装饰器,生成器,迭代器

發(fā)布時(shí)間:2025/3/21 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 装饰器,生成器,迭代器 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 裝飾器
    • 什么是裝飾器
    • 為什么使用裝飾器
    • 裝飾器的使用場景
      • 用戶認(rèn)證,判斷用戶是否登錄
      • 計(jì)算函數(shù)運(yùn)行時(shí)間(算是一個(gè)功能,在項(xiàng)目中用的不多)
      • 記錄日志
      • redis緩存
      • 裝飾器1----能夠適應(yīng)90%的業(yè)務(wù)需求
      • 裝飾器2----對(duì)特定網(wǎng)頁進(jìn)行身份驗(yàn)證
      • 裝飾器3----終極篇:實(shí)現(xiàn)對(duì)不同網(wǎng)頁不同方式的身份認(rèn)證
      • 三級(jí)裝飾器
    • 常用的內(nèi)置裝飾器
    • 使用閉包實(shí)現(xiàn)裝飾器功能
    • python裝飾器補(bǔ)充之functools包中的wraps
  • 生成器
    • 生成器的定義
    • 為什么使用生成器
    • 生成器的工作原理
    • yield生成器運(yùn)行機(jī)制
    • yield實(shí)現(xiàn)單線程下的并發(fā)效果
  • 迭代器
    • 迭代器的定義
    • 迭代器的兩個(gè)基本方法:
    • 迭代器和生成器的區(qū)別

裝飾器

什么是裝飾器

  • 裝飾器本身是函數(shù),用來給其他函數(shù)添加新的功能
  • 特點(diǎn):不修改調(diào)用方式,不修改源代碼

為什么使用裝飾器

  • 使用方便
  • 節(jié)省開發(fā)時(shí)間

裝飾器的使用場景

用戶認(rèn)證,判斷用戶是否登錄

user,passwd = 'aaa','123' def auth(func):def wrapper(username,password,*args,**kwargs):if user == username and password == passwd:print("User has passed authentication")res = func(username,password,*args,**kwargs) #這里執(zhí)行func()相當(dāng)于執(zhí)行調(diào)用的函數(shù)如home()return res #為了獲得home()函數(shù)返回值,可以將執(zhí)行結(jié)果賦值給res然后返回print(home())結(jié)果是"from home"而不是"None"了else:raise ValueError("非合法用戶")return wrapper@auth def home(username,password):print("welcome to home page")return "from home"home('aaa','123')

計(jì)算函數(shù)運(yùn)行時(shí)間(算是一個(gè)功能,在項(xiàng)目中用的不多)

記錄日志

#! /usr/bin/env python # -*- coding: utf-8 -*- from functools import wraps import traceback def decoratore(func):@wraps(func)def log(*args,**kwargs):try:print("當(dāng)前運(yùn)行方法",func.__name__)return func(*args,**kwargs)except Exception as e:print(traceback.format_exc()) # 這里應(yīng)該調(diào)用log模塊來記錄到日志里return log@decoratore def test():int('a')passif __name__ == '__main__':test()''' 上面運(yùn)行結(jié)果當(dāng)前運(yùn)行方法 testTraceback (most recent call last):File "C:/Users/tom/Desktop/alipay_demo/aaa/t2.py", line 11, in logreturn func(*args,**kwargs)File "C:/Users/tom/Desktop/alipay_demo/aaa/t2.py", line 18, in testint('a')ValueError: invalid literal for int() with base 10: 'a'22222'''

redis緩存

第一步:查詢r(jià)edis緩存是否存在這個(gè)key
第二步:如果存在這個(gè)key,不用去mysql中查詢,直接從redis中取出數(shù)據(jù)即可(減輕了mysql壓力)
第三步:如果查詢的key不存在,然后到mysql中查詢數(shù)據(jù),讓后設(shè)置到redis中,下次查詢就有了

# coding:utf-8 from django.core.cache import cache# 獲取redis緩存的裝飾器 def redis_cache(key, timeout):def __redis_cache(func):def warpper(*args, **kw):if cache.has_key(key): # 判斷緩存是否存在data = cache.get(key)else:# 若不存在則執(zhí)行獲取數(shù)據(jù)的方法# 注意返回?cái)?shù)據(jù)的類型(字符串,數(shù)字,字典,列表均可)data = func(*args, **kw) # 從數(shù)據(jù)庫查詢到數(shù)據(jù)設(shè)置到redis中cache.set(key, data, timeout)return datareturn warpperreturn __redis_cache#鍵值為test,超時(shí)時(shí)間為60秒 @redis_cache('test', 60) def get_test_data():# 獲取Blog模型隨機(jī)排序前3條數(shù)據(jù)# (Blog模型是我自己的模型,具體代碼根據(jù)自己需求獲取數(shù)據(jù))# values執(zhí)行結(jié)果,將返回一個(gè)字典。字典可以直接存入redis# data = Blog.objects.values('id', 'caption').order_by('?')[:3]data = '從數(shù)據(jù)庫查詢到了數(shù)據(jù)'return dataif __name__ == '__main__':get_test_data()

裝飾器1----能夠適應(yīng)90%的業(yè)務(wù)需求

在裝飾器中 @timer等價(jià)于 test1=timer(test1)

1. 在timer()函數(shù)中返回值是return deco

2. 所以timer(test1)作用是將函數(shù)test1內(nèi)存地址當(dāng)做參數(shù)傳遞給timer()

3. timer() 函數(shù)最后將運(yùn)行后的函數(shù)deco內(nèi)存地址作為返回值返回

4. test1=timer(test1)作用就是將將deco函數(shù)內(nèi)存地址賦值給test1,所以最后運(yùn)行test1()就相當(dāng)于運(yùn)行deco()

5. 所以最后調(diào)用時(shí)給test2()傳入?yún)?shù)就相當(dāng)于給deco傳入?yún)?shù)

import time def timer(func): #timer(test1) func=test1def deco(*args,**kwargs):start_time = time.time()func(*args,**kwargs) #run test1stop_time = time.time()print("running time is %s"%(stop_time-start_time))return deco @timer # test1=timer(test1) def test1():time.sleep(3)print("in the test1") @timer def test2(name):print("in the test2",name) test1() test2("tom")

裝飾器2----對(duì)特定網(wǎng)頁進(jìn)行身份驗(yàn)證

import time user,passwd = 'aaa','123' def auth(func):def wrapper(*args,**kwargs):username = input("Username:").strip()password = input("Password:").strip()if user == username and password == passwd:print("User has passed authentication")res = func(*args,**kwargs) #這里執(zhí)行func()相當(dāng)于執(zhí)行調(diào)用的函數(shù)如home()return res #為了獲得home()函數(shù)返回值,可以將執(zhí)行結(jié)果賦值給res然后返回print(home())結(jié)果是"from home"而不是"None"了else:exit("Invalid username or password")return wrapper def index():print("welcome to index page") @auth def home():print("welcome to home page")return "from home" @auth def bbs():print("welcome to bbs page") index() print(home()) #在這里調(diào)用home()相當(dāng)于調(diào)用wrapper() bbs()

裝飾器3----終極篇:實(shí)現(xiàn)對(duì)不同網(wǎng)頁不同方式的身份認(rèn)證

@auth(auth_type=“l(fā)ocal”)代碼作用

  • 在上面的代碼中使用@auth相當(dāng)于先將home函數(shù)的內(nèi)存地址當(dāng)做變量傳入auth()函數(shù),執(zhí)行結(jié)果后home()相當(dāng)于wrapper()
  • 而在這里驗(yàn)證的時(shí)候猶豫@auth(auth_type=“l(fā)ocal”)中有()括號(hào),那么就相當(dāng)于將執(zhí)行auth()函數(shù)而且是將auth_type="local當(dāng)做參數(shù)傳入到auth()函數(shù)執(zhí)行
  • 所以outer_wrapper函數(shù)也會(huì)執(zhí)行,outer_wrapper函數(shù)的執(zhí)行結(jié)果返回的就是wrapper()函數(shù)的內(nèi)存地址
  • 所以最終結(jié)果同樣是執(zhí)行home()函數(shù)就相當(dāng)于執(zhí)行wrapper函數(shù)
  • 但是有所不同的是著這個(gè)版本中我們可以在外層的auth函數(shù)中傳入新的參數(shù)幫組我們根據(jù)需求判斷
import time user,passwd = 'aaa','123' def auth(auth_type):print("auth func:",auth_type)def outer_wrapper(func):def wrapper(*args, **kwargs):print("wrapper func args:", *args, **kwargs)if auth_type == "local":username = input("Username:").strip()password = input("Password:").strip()if user == username and passwd == password:print("\033[32;1mUser has passed authentication\033[0m")res = func(*args, **kwargs) # from homeprint("---after authenticaion ")return reselse:exit("\033[31;1mInvalid username or password\033[0m")elif auth_type == "ldap":print("搞毛線ldap,不會(huì)。。。。")return wrapperreturn outer_wrapperdef index():print("welcome to index page") @auth(auth_type="local") # home = wrapper() def home():print("welcome to home page")return "from home"@auth(auth_type="ldap") def bbs():print("welcome to bbs page")index() print(home()) #wrapper() bbs()

三級(jí)裝飾器

#! /usr/bin/env python # -*- coding: utf-8 -*- import time def auth(auth_type):print("auth func:",auth_type)def outer_wrapper(func):def wrapper(*args, **kwargs):print("wrapper func args:", *args, **kwargs)print('運(yùn)行前')func(*args, **kwargs)print('運(yùn)行后')return wrapperreturn outer_wrapper@auth(auth_type="local") # home = wrapper() def home():print("welcome to home page")return "from home" home()

常用的內(nèi)置裝飾器

  • staticmethod
    類似實(shí)現(xiàn)了靜態(tài)方法 注入以后,可以直接 : 類名.方法
  • property
    經(jīng)過property裝飾過的函數(shù) 不再是一個(gè)函數(shù),而是一個(gè)property,類似實(shí)現(xiàn)get,set方法
1 @property 2 def width(self): 3 return self.__width 4 5 @width.setter 6 def width(self, newWidth): 7 self.__width = newWidth

使用閉包實(shí)現(xiàn)裝飾器功能

閉包概念

  • 在一個(gè)外函數(shù)中定義了一個(gè)內(nèi)函數(shù),內(nèi)函數(shù)里運(yùn)用了外函數(shù)的臨時(shí)變量,并且外函數(shù)的返回值是內(nèi)函數(shù)的引用,這樣就構(gòu)成了一個(gè)閉包
  • 一般情況下,在我們認(rèn)知當(dāng)中,如果一個(gè)函數(shù)結(jié)束,函數(shù)的內(nèi)部所有東西都會(huì)釋放掉,還給內(nèi)存,局部變量都會(huì)消失
  • 但是閉包是一種特殊情況,如果外函數(shù)在結(jié)束的時(shí)候發(fā)現(xiàn)有自己的臨時(shí)變量將來會(huì)在內(nèi)部函數(shù)中用到,就把這個(gè)臨時(shí)變量綁定給了內(nèi)部函數(shù),然后自己再結(jié)束
#! /usr/bin/env python # -*- coding: utf-8 -*- import timedef timer(func): #timer(test1) func=test1def deco(*args,**kwargs): # # 函數(shù)嵌套start_time = time.time()func(*args,**kwargs) # 跨域訪問,引用了外部變量func (func實(shí)質(zhì)是函數(shù)內(nèi)存地址)stop_time = time.time()print "running time is %s"%(stop_time-start_time)return deco # 內(nèi)層函數(shù)作為外層函數(shù)返回值def test(name):print "in the test2",nametime.sleep(2)test = timer(test) # 等價(jià)于 ==》 @timer語法糖 test("tom") ''' 運(yùn)行結(jié)果: in the test2 tom running time is 2.00302696228 '''

python裝飾器補(bǔ)充之functools包中的wraps

Python被裝飾函數(shù)其實(shí)已經(jīng)是另外一個(gè)函數(shù)

#! /usr/bin/env python # -*- coding: utf-8 -*- def login_required(view_func):def wrapper(*args,**kwargs):passreturn wrapper@login_required def test1():'''test1...'''print('test1')print (test1.__name__) # 結(jié)果:wrapper (標(biāo)識(shí)test1函數(shù)已經(jīng)變成wrapper函數(shù)了)

使用functools的wrap,它能保留原有函數(shù)的名稱

#! /usr/bin/env python # -*- coding: utf-8 -*- from functools import wrapsdef login_required(view_func):@wraps(view_func)def wrapper(*args,**kwargs):passreturn wrapper@login_required def test1():'''test1...'''print('test1')print (test1.__name__) # 結(jié)果:test1 (解決了改變函數(shù)的問題,能保留原有函數(shù)的名稱)

生成器

生成器的定義

  • 生成器,即生成一個(gè)容器
  • 生成器就是一個(gè)特殊的迭代器
  • 在Python中,一邊循環(huán),一邊計(jì)算的機(jī)制,稱為生成器。
  • 生成器可以理解為一種數(shù)據(jù)類型,這種數(shù)據(jù)類型自動(dòng)實(shí)現(xiàn)了迭代器協(xié)議(其他數(shù)據(jù)類型需要調(diào)用自己的內(nèi)置iter() 方法或__iter__()的內(nèi)置函數(shù))所以,生成器就是一個(gè)可迭代對(duì)象

為什么使用生成器

  • 節(jié)省空間
  • 高效

生成器的工作原理

  • 生成器是這樣一個(gè)函數(shù),它記住上一次返回時(shí)在函數(shù)體中的位置
  • 對(duì)生成器函數(shù)的第二次(或第 n 次)調(diào)用跳轉(zhuǎn)至該函數(shù)中間,而上次調(diào)用的所有局部變量都保持不變
  • 生成器不僅“記住”了它數(shù)據(jù)狀態(tài);生成器還“記住”了它在流控制構(gòu)造(在命令式編程中,這種構(gòu)造不只是數(shù)據(jù)值)中的位置
  • 生成器是一個(gè)函數(shù),而且函數(shù)的參數(shù)都會(huì)保留
  • 迭代到下一次的調(diào)用時(shí),所使用的參數(shù)都是第一次所保留下的,即是說,在整個(gè)所有函數(shù)調(diào)用的參數(shù)都是第一次所調(diào)用時(shí)保留的,而不是新創(chuàng)建的

生成器的場景應(yīng)用?

  • 生成器是一個(gè)概念,我們平常寫代碼可能用的并不多,但是python源碼大量使用
  • 比如我們tornado框架就是基于 生成器+協(xié)程
  • 在我們代碼中使用舉例
    比如我們要生成一百萬個(gè)數(shù)據(jù),如果用生成器非常節(jié)省空間,用列表浪費(fèi)大量空間
  • import time t1 = time.time() g = (i for i in range(100000000)) t2 = time.time() lst = [i for i in range(100000000)] t3 = time.time() print('生成器時(shí)間:',t2 - t1) # 生成器時(shí)間: 0.0 print('列表時(shí)間:',t3 - t2) # 列表時(shí)間: 5.821957349777222

    yield生成器運(yùn)行機(jī)制

  • 在Python中,yield就是這樣的一個(gè)生成器。
  • 當(dāng)你問生成器要一個(gè)數(shù)時(shí),生成器會(huì)執(zhí)行,直至出現(xiàn) yield 語句,生成器把yield 的參數(shù)給你,之后生成器就不會(huì)往下繼續(xù)運(yùn)行
  • 當(dāng)你問他要下一個(gè)數(shù)時(shí),他會(huì)從上次的狀態(tài)開始運(yùn)行,直至出現(xiàn)yield語句,把參數(shù)給你,之后停下。如此反復(fù)
  • 在python中,當(dāng)你定義一個(gè)函數(shù),使用了yield關(guān)鍵字時(shí),這個(gè)函數(shù)就是一個(gè)生成器
  • 它的執(zhí)行會(huì)和其他普通的函數(shù)有很多不同,函數(shù)返回的是一個(gè)對(duì)象,而不是你平常所用return語句那樣,能得到結(jié)果值。如果想取得值,那得調(diào)用next()函數(shù)
  • 每當(dāng)調(diào)用一次迭代器的next函數(shù),生成器函數(shù)運(yùn)行到y(tǒng)ield之處,返回yield后面的值且在這個(gè)地方暫停,所有的狀態(tài)都會(huì)被保持住,直到下次next函數(shù)被調(diào)用,或者碰到異常循環(huán)退出
  • 使用yield函數(shù)實(shí)現(xiàn)斐波那契數(shù)列

    def fib(max_num):a,b = 1,1while a < max_num:yield ba,b=b,a+bg = fib(10) #生成一個(gè)生成器:[2, 3, 5, 8, 13] print(g.__next__()) #第一次調(diào)用返回:1 print(list(g))

    生成器讀寫文件:

    #!/usr/bin/python # -*- coding: utf-8 -*- def read_big_file_v(fname):block_size = 1024 * 8with open(fname,encoding="utf8") as fp:while True:chunk = fp.read(block_size)# 當(dāng)文件沒有更多內(nèi)容時(shí),read 調(diào)用將會(huì)返回空字符串 ''if not chunk:breakprint(chunk) path = r'C:\aaa\luting\edc-backend\tttt.py' read_big_file_v(path)

    yield實(shí)現(xiàn)單線程下的并發(fā)效果

    • yield相當(dāng)于 return 返回一個(gè)值,并且記住這個(gè)返回的位置,下次迭代時(shí),代碼從yield的下一條語句開始執(zhí)行。
    • send() 和next()一樣,都能讓生成器繼續(xù)往下走一步(下次遇到y(tǒng)ield停),但send()能傳一個(gè)值,這個(gè)值作為yield表達(dá)式整體的結(jié)果

    迭代器

    迭代器的定義

    • 迭代器是訪問集合元素的一種方式
    • 所謂的迭代器就是具有next方法的對(duì)象。
    • 迭代器對(duì)象從集合的第一個(gè)元素開始訪問,直到所有的元素被訪問完結(jié)束。迭代器只能往前不會(huì)后退。使用inter()函數(shù)創(chuàng)建迭代器
    • 迭代器僅是一容器對(duì)象,它實(shí)現(xiàn)了迭代器協(xié)議

    迭代器的兩個(gè)基本方法:

    ① next方法
      返回容器的下一個(gè)元素
      
    ② __iter__方法
      返回迭代器自身

    • 在調(diào)用next方法時(shí),迭代器會(huì)返回它的下一個(gè)值,如果next方法被調(diào)用,但迭代器中沒有值可以返就會(huì)引發(fā)一個(gè)StopIteration異常
    a = iter([1,2,]) #生成一個(gè)迭代器 print(a.__next__()) print(a.__next__()) print(a.__next__()) #在這一步會(huì)引發(fā) “StopIteration” 的異常

    迭代器和可迭代對(duì)象

  • 凡是可作用于for循環(huán)的對(duì)象都是可迭代的(Iterable)類型;
  • 凡是可作用于next()函數(shù)的對(duì)象都是迭代器(Iterator)類型,它們表示一個(gè)惰性計(jì)算的序列;
  • 集合數(shù)據(jù)類型如list、dict、str等是可迭代的但不是迭代器,不過可以通過iter()函數(shù)獲得一個(gè)Iterator對(duì)象。
  • Python的for循環(huán)本質(zhì)上就是通過不斷調(diào)用next()函數(shù)實(shí)現(xiàn)的
  • 一個(gè)實(shí)現(xiàn)了__iter__方法的對(duì)象是可迭代的,一個(gè)實(shí)現(xiàn)next方法的對(duì)象是迭代器
  • 迭代器和生成器的區(qū)別

    • 在使用生成器時(shí),創(chuàng)建一個(gè)函數(shù),在使用迭代器時(shí),使用內(nèi)置函數(shù)iter()和next(),在生成器中,使用關(guān)鍵字‘yield’來每次生成/返回一個(gè)對(duì)象
    • 每次’yield’暫停循環(huán)時(shí),生成器會(huì)保存本地變量的狀態(tài),而迭代器并不會(huì)使用局部變量,只需要一個(gè)可迭代對(duì)象進(jìn)行迭代
    • 使用類可以實(shí)現(xiàn)迭代器,但無法實(shí)現(xiàn)生成器,生成器運(yùn)行速度快,語法簡單,迭代器更能節(jié)約內(nèi)存
    list = [1,2,3,4,5] # 列表是一個(gè)可迭代對(duì)象,不是一個(gè)迭代器 print dir(list) # 所以 list 中有 __iter__() 方法,沒有 __next__()方法 iter_obj = list.__iter__() # __iter__()方法返回迭代器對(duì)象本身(這個(gè)迭代器對(duì)象就會(huì)有 next 方法了)print '###################################\n' print iter_obj.next() # 1 print iter_obj.next() # 2 print iter_obj.next() # 3

    判斷是迭代器和可迭代對(duì)象

    注:列表,元組,字典是可迭代的但不是迭代器

    from collections import Iterable print(isinstance([],Iterable)) #True print(isinstance({},Iterable)) #True print(isinstance((),Iterable)) #True print(isinstance("aaa",Iterable)) #True print(isinstance((x for x inrange(10)),Iterable)) #True

    列表不是迭代器,只有生成器是迭代器

    from collections import Iterator t = [1,2,3,4] print(isinstance(t,Iterator)) #False t1 = iter(t) print(isinstance(t1,Iterator)) #True

    自定義迭代器

    class MyRange(object):def __init__(self, n):self.idx = 0self.n = ndef __iter__(self):return selfdef next(self):if self.idx < self.n:val = self.idxself.idx += 1return self.n[val]else:raise StopIteration()l = [4,5,6,7,8] obj = MyRange(l) print obj.next() # 4 print obj.next() # 5 print obj.next() # 6

    總結(jié)

    以上是生活随笔為你收集整理的装饰器,生成器,迭代器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。