日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

装饰器,生成器,迭代器

發布時間:2025/3/21 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 装饰器,生成器,迭代器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

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

裝飾器

什么是裝飾器

  • 裝飾器本身是函數,用來給其他函數添加新的功能
  • 特點:不修改調用方式,不修改源代碼

為什么使用裝飾器

  • 使用方便
  • 節省開發時間

裝飾器的使用場景

用戶認證,判斷用戶是否登錄

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) #這里執行func()相當于執行調用的函數如home()return res #為了獲得home()函數返回值,可以將執行結果賦值給res然后返回print(home())結果是"from home"而不是"None"了else:raise ValueError("非合法用戶")return wrapper@auth def home(username,password):print("welcome to home page")return "from home"home('aaa','123')

計算函數運行時間(算是一個功能,在項目中用的不多)

記錄日志

#! /usr/bin/env python # -*- coding: utf-8 -*- from functools import wraps import traceback def decoratore(func):@wraps(func)def log(*args,**kwargs):try:print("當前運行方法",func.__name__)return func(*args,**kwargs)except Exception as e:print(traceback.format_exc()) # 這里應該調用log模塊來記錄到日志里return log@decoratore def test():int('a')passif __name__ == '__main__':test()''' 上面運行結果當前運行方法 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緩存

第一步:查詢redis緩存是否存在這個key
第二步:如果存在這個key,不用去mysql中查詢,直接從redis中取出數據即可(減輕了mysql壓力)
第三步:如果查詢的key不存在,然后到mysql中查詢數據,讓后設置到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:# 若不存在則執行獲取數據的方法# 注意返回數據的類型(字符串,數字,字典,列表均可)data = func(*args, **kw) # 從數據庫查詢到數據設置到redis中cache.set(key, data, timeout)return datareturn warpperreturn __redis_cache#鍵值為test,超時時間為60秒 @redis_cache('test', 60) def get_test_data():# 獲取Blog模型隨機排序前3條數據# (Blog模型是我自己的模型,具體代碼根據自己需求獲取數據)# values執行結果,將返回一個字典。字典可以直接存入redis# data = Blog.objects.values('id', 'caption').order_by('?')[:3]data = '從數據庫查詢到了數據'return dataif __name__ == '__main__':get_test_data()

裝飾器1----能夠適應90%的業務需求

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

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

2. 所以timer(test1)作用是將函數test1內存地址當做參數傳遞給timer()

3. timer() 函數最后將運行后的函數deco內存地址作為返回值返回

4. test1=timer(test1)作用就是將將deco函數內存地址賦值給test1,所以最后運行test1()就相當于運行deco()

5. 所以最后調用時給test2()傳入參數就相當于給deco傳入參數

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----對特定網頁進行身份驗證

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) #這里執行func()相當于執行調用的函數如home()return res #為了獲得home()函數返回值,可以將執行結果賦值給res然后返回print(home())結果是"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()) #在這里調用home()相當于調用wrapper() bbs()

裝飾器3----終極篇:實現對不同網頁不同方式的身份認證

@auth(auth_type=“local”)代碼作用

  • 在上面的代碼中使用@auth相當于先將home函數的內存地址當做變量傳入auth()函數,執行結果后home()相當于wrapper()
  • 而在這里驗證的時候猶豫@auth(auth_type=“local”)中有()括號,那么就相當于將執行auth()函數而且是將auth_type="local當做參數傳入到auth()函數執行
  • 所以outer_wrapper函數也會執行,outer_wrapper函數的執行結果返回的就是wrapper()函數的內存地址
  • 所以最終結果同樣是執行home()函數就相當于執行wrapper函數
  • 但是有所不同的是著這個版本中我們可以在外層的auth函數中傳入新的參數幫組我們根據需求判斷
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,不會。。。。")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()

三級裝飾器

#! /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('運行前')func(*args, **kwargs)print('運行后')return wrapperreturn outer_wrapper@auth(auth_type="local") # home = wrapper() def home():print("welcome to home page")return "from home" home()

常用的內置裝飾器

  • staticmethod
    類似實現了靜態方法 注入以后,可以直接 : 類名.方法
  • property
    經過property裝飾過的函數 不再是一個函數,而是一個property,類似實現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

使用閉包實現裝飾器功能

閉包概念

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

python裝飾器補充之functools包中的wraps

Python被裝飾函數其實已經是另外一個函數

#! /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__) # 結果:wrapper (標識test1函數已經變成wrapper函數了)

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

#! /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__) # 結果:test1 (解決了改變函數的問題,能保留原有函數的名稱)

生成器

生成器的定義

  • 生成器,即生成一個容器
  • 生成器就是一個特殊的迭代器
  • 在Python中,一邊循環,一邊計算的機制,稱為生成器。
  • 生成器可以理解為一種數據類型,這種數據類型自動實現了迭代器協議(其他數據類型需要調用自己的內置iter() 方法或__iter__()的內置函數)所以,生成器就是一個可迭代對象。

為什么使用生成器

  • 節省空間
  • 高效

生成器的工作原理

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

生成器的場景應用?

  • 生成器是一個概念,我們平常寫代碼可能用的并不多,但是python源碼大量使用
  • 比如我們tornado框架就是基于 生成器+協程
  • 在我們代碼中使用舉例
    比如我們要生成一百萬個數據,如果用生成器非常節省空間,用列表浪費大量空間
  • 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('生成器時間:',t2 - t1) # 生成器時間: 0.0 print('列表時間:',t3 - t2) # 列表時間: 5.821957349777222

    yield生成器運行機制

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

    def fib(max_num):a,b = 1,1while a < max_num:yield ba,b=b,a+bg = fib(10) #生成一個生成器:[2, 3, 5, 8, 13] print(g.__next__()) #第一次調用返回: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)# 當文件沒有更多內容時,read 調用將會返回空字符串 ''if not chunk:breakprint(chunk) path = r'C:\aaa\luting\edc-backend\tttt.py' read_big_file_v(path)

    yield實現單線程下的并發效果

    • yield相當于 return 返回一個值,并且記住這個返回的位置,下次迭代時,代碼從yield的下一條語句開始執行。
    • send() 和next()一樣,都能讓生成器繼續往下走一步(下次遇到yield停),但send()能傳一個值,這個值作為yield表達式整體的結果

    迭代器

    迭代器的定義

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

    迭代器的兩個基本方法:

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

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

    迭代器和可迭代對象

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

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

    判斷是迭代器和可迭代對象

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

    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

    總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。