1. 程式人生 > >Python初探第二篇-裝飾器和叠代器,生成器

Python初探第二篇-裝飾器和叠代器,生成器

decorate name 返回 -s 調用 手動 新功能 函數的調用 賦值

一,裝飾器

  1,概念

  裝飾器就是給已有的模塊添加新的功能,如登錄驗證功能,運行時間功能等。本身可以是任意可調用對象,被裝飾者也可以是任意可調用對象。
  強調裝飾器的原則:1 不修改被裝飾對象的源代碼 2 不修改被裝飾對象的調用方式
  裝飾器的目標:在遵循1和2的前提下,為被裝飾對象添加上新功能

  2,理論基礎

  要想實現裝飾器的功能,我們需要三個理論基礎:函數閉包+函數嵌套+高階函數。我們通過為如下模塊加入統計運行時間的裝飾器來講解如何使用

import time
def test_func():
    for i in range(5):
        time.sleep(
0.5)

  3,推導

  首先我們知道要知道函數的運行時間,只需要在函數前後加上當前時間,通過差值就能計算出來。因此我們可以定義一個模塊,並傳入所求的函數的函數地址,即高階函數。

  模塊中包含此函數的調用和統計時間的功能

import time

def test_func():
    for i in range(5):
        time.sleep(0.5)

def decorate(func):
    start_time = time.time()
    func()
    end_time = time.time()
    print(end_time-start_time)

decorate(test_func)   
#2.5s

  這樣就實現了統計時間的功能,但是卻修改了函數的調用邏輯,因此進一步思考,我們可以在裝飾器函數內定義函數,並在此函數內調用被統計函數,即函數嵌套,並返回

代碼 如下:

import time
def test_func():
    for i in range(5):
        time.sleep(0.5)
def decorate(func):
    def count_time():
        start_time = time.time()
        func()
        end_time = time.time()
        
print(end_time-start_time) return count_time test_func = decorate(test_func) test_func()

而python給我們提供了裝飾器語法:

import time

def decorate(func):
    def count_time():
        start_time = time.time()
        func()
        end_time=time.time()
        print(end_time-start_time)
    return count_time

@decorate 
def test_func():
    for i in range(5):
        time.sleep(0.5)

test_func()

上面就實現了一個簡單的裝飾器,可根據需求來增加它的功能,如傳入參數,返回值等。

二,叠代器

  1,概念

  叠代器(iteretor)是一種遍歷容器所有或者部分元素的方法,相當於一個復雜的指針,能夠遍歷復雜的數據結構,一個容器也應該提供它自己的叠代器。

  2,叠代器對象與可叠代對象

   叠代器對象:即對象能夠提供遍歷它的方法,像是叠代器的一種具體表現,在Python中叠代器對象能夠提供__iter__和__next__方法來得到容器中下一個元素的值。

   可叠代對象:即對象提供__iter__方法,使用該方法後得到叠代器對象,如字符串,列表元組

li=[1,2,3,4,5]
li=li.__iter__()  # 可叠代對象轉化成叠代器對象
print(li.__next__())  # 1

  3,使用方法  

dic = {"a": 1, "e": 4, "b": 2, "c": 3, "d": 4}
iter_dic = dic.__iter__()
# while True:
try:
    print(next(iter_dic))   #"a" "e" "b".....
except StopIteration:     #需要手動捕捉異常
    break

  而我們可以借助Python中強大的for循環機制來循環遍歷容器

  4,for循環

#基於for循環,我們可以完全不再依賴索引去取值了
dic = {a:1,b:2,c:3}
for k in dic:
    print(dic[k])

#for循環的工作原理
#1:執行in後對象的dic.__iter__()方法,叠代器對象.__iter,返回對象本身。得到一個叠代器對象iter_dic
#2: 執行next(iter_dic),將得到的值賦值給k,然後執行循環體代碼
#3: 重復過程2,直到捕捉到異常StopIteration,結束循環

三,生成器

  Python使用生成器能夠實現延時操作,何謂延時操作,即需要結果時就產生結果,不需要時就不產生。提供生成器對象有兩種方式:

  1,生成器函數:和常規的函數定義一樣只不過不用return,而是使用yield來返回結果。一次只返回一個結果,在每個結果中間,掛起函數狀態,以便下次繼續返回。

  2,生成器表達式:生成一個生成器對象,按需產生結果,就是叠代的時候產生具體的值。

  1,生成器函數  

def gensquares(n):
    for i in range(n):
        yield i ** 2


obj = gensquares(5)
print(obj)  # <generator object gensquares at 0x00000000021E55C8>
print(next(obj))  # 0
print(next(obj))  # 1
print(next(obj))  # 4

  2,生成器表達式

li = []
for i in range(5):
    name = "name%d" % i
    li.append(name)
print(li)  # [‘name0‘, ‘name1‘, ‘name2‘, ‘name3‘, ‘name4‘]
# 列表推導
li = ["name%d" % i for i in range(5)]
print(li)  # [‘name0‘, ‘name1‘, ‘name2‘, ‘name3‘, ‘name4‘]
# 簡潔了許多

# 生成器表達式
gens = ("name%d" % i for i in range(5))
print(gens)  # <generator object <genexpr> at 0x00000000028655C8>
print(next(gens))  # name0
print(next(gens))  # name1
print(next(gens))  # name2
#生成器對象就是叠代器對象

使用生成器的好處數據不會直接加載到內存,在數據量很大的情況下作用很大。比如使用內置函數如下

#print(sum([i for i in range(100000000)])) #提示計算機內存不足,程序崩潰
print(sum((i for i in range(1000000000)))) #程正常運行

註意事項:生成器對象是一種叠代器對象,它們都只能遍歷一次,而可叠代對象可以多次遍歷。

Python初探第二篇-裝飾器和叠代器,生成器