Python 全棧開發五 迭代器 生成器 裝飾器


一、迭代器

迭代協議:對象必須提供一個next方法,執行該方法后會返回迭代的下一項或者拋出Stopiteration異常,終止迭代。切只能往前,不能倒退。

可迭代對象:遵循迭代協議的對象就是可迭代對象。

迭代器是一個可以記住遍歷的位置的對象。迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會后退。

迭代器有兩個基本的方法:iter() 和 next()

字符串,列表或元組對象都可用於創建迭代器,生成迭代器的方法是iter():

1 li = [1,2,3,4]
2 #inter()本質調用了內置的__iter__
3 a = li.__iter__()  #生產一個可迭代對象
4 #next()本質調用__next__()
5 a.__next__()       #對可迭代對象進行取值

方法二:

>>li = [1,2,3,4,5]
>>it = iter(li)     #生成一個迭代器
>>it.__next__()
1
>>next(it)  #以上兩種next都可以使用
2
>>for i in it:
        print(i)
3
4
5
#迭代完畢后,迭代器里面的數據就沒有了
>> type(it)
<class 'list_iterator'>   #類型是迭代器類型

 

二、生成器

在描述生成器前我們先來了解列表生成式:

#普通定義的列表直接把列表寫死
li = [1,2,3,4,5]

#使用列表生成式,可以為列表添加一些新的屬性

li1 = [a*a for a in range(10)]
print(li1)

#也可以用以下兩種方法方法

li2 = list(map(lambda x:x+1,li))
print(li2)


a = []
for i in range(10):
    a.append(i+1)
print(a)

#從以上對比可以看出,使用第二種方法代碼最為簡單,即列表生成式

  雖然有列表生成式,可以簡化生成特定列表的操作,但是當列表數據過大,就會過度的消耗內存,並且列表是數據也不會一直使用,在python中有一種一邊循環一邊計算的機制就是生成器。

生成器的第一種表現形式:

#創建一個生成器

li = (a*a for a in range(10))

print(li) #<generator object <genexpr> at 0x00000000027BD468>,返回一個生成器對象,用next調用對象
print(li.__next__())
print(next(li))  #且只能調用一次,不能往回調用

'''我們講過,generator保存的是算法,每次調用next(g),
就計算出g的下一個元素的值,直到計算到最后一個元素,沒有更多的元素時,
拋出StopIteration的錯誤。一般情況下,我們用for循環來調用全部數據'''

for i in li:
    print(i)

 

生成器的第二種表現形式:

  生成器:一個函數調用時返回一個迭代器,那這個函數就叫做生成器(generator),如果函數中包含yield語法,那這個函數就會變成生成器 跟普通函數不同的是,生成器是一個返回迭代器的函數,只能用於迭代操作,更簡單點理解生成器就是一個迭代器。調用一個生成器函數,返回的是一個迭代器對象。

  yield語法:每當行數運行到yield是就會中斷並且保存當前所有的運行信息,並且在執行next()方法后繼續從中斷的地方運行。

#生成一個斐波拉契數列
def fib(max):
    a,b,n = 0,0,1
    while n < max:
        a, b = b,a+b
        n +=1
    return 'done'

c = fib(5)
print(c)
#弊端,會直接全部生成

#把該函數變為一個生成器
def fib2(max):
    a,b,n = 0,0,1
    while n < max:
        yield b    #遇到一次返回一次,再次激活則運行后面的代碼,用next激活
        a, b = b,a+b
        n +=1

d = fib2(5)
print(next(d))

下面是一個利用yield實現的一種單線程下的並發效果,也可以理解為一協程(后面會講這一內容):

import time

def consumer(name):
    print('%s准備吃包子了!' % name)
    while True:
        baozi = yield               # 保存當前狀態的值,並且退出函數
        print('包子[%s]來了,被[%s]吃了!'% (baozi,name))

# c = consumer('alix')   生成一個生成器對象
# c.__next__()        調用生成器

def producer():
    c = consumer('a')
    c2 = consumer('b')
    c.__next__()
    c2.__next__()
    print('老子開始准備做包子了')
    for i in range(10):
        time.sleep(1)
        print('做了1個包子,分兩半')
        c.send(i)               #給yield傳值,並且喚醒yield
        c2.send(i)
producer()

三、裝飾器

裝飾器:本質上就是函數,作用就是為其他函數添加其他功能
原則:1、不能修改被裝飾的函數的源代碼
2、不能修改被修飾函數的調用方式

在將裝飾器前我們進行一些裝飾器的知識儲備:

1.函數即'變量'
2.高階函數
1.把一個函數名當做實參傳給另一個函數(添加功能不修改函數的源代碼)
2.返回值中包含函數名(不修改函數的調用方式)
3.嵌套函數

函數即“變量”:

函數定義好后就像變量一樣存儲在內存中,當我們去調用的時候才會有意義。

#函數即變量

# def foo():
#     print('in the foo')
# foo()

#即無需考慮函數的定義順序,就和定義變量一樣

def bar():
    print('in the bar')
def foo():
    print('in the foo')
    bar()
foo()

高階函數:即把一個函數名當做實參傳遞給函數,就類似有把一個變量名傳遞給函數。

# 高階函數:把一個函數名,當做實參傳給函數
import time
def bar():
    time.sleep(3)    #暫停3秒
    print('in the bar')

def text1(fun):
    start_time = time.time()   #起始時間
    fun()
    stop_time = time.time()    #結束時間
    print('the fun time is %s' % (stop_time-start_time))  #計算出fun()所用的時間

text1(bar)  #將該函數名傳遞進去


def bar2():
    time.sleep(3)
    print('in the bar2')

def text2(fun):
    print(fun)
    return fun

bar2 = text2(bar2)
bar2()

通過高階函數的作用可以看出:在不改變函數的源代碼的情況下,給函數增加了計時的功能

嵌套函數:

def foo():
    print('in the foo')
    def bar():
        print('in the bar')
    bar()
foo()

結合以上三種實現裝飾器:

import time
def timer(func): #timer(text1)   func=text1    裝飾器函數
    def wrapper(*args,**kwargs):
        start_time = time.time()
        func()              #run text1
        stop_time = time.time()
        print('the fun run time is %s' % (stop_time-start_time))
    return wrapper

@timer   # text1 = timer(text1)  這一步就是把text1傳入timer
def text1():
    time.sleep(1)
    print('the is text1')

text1()

帶參數的裝飾器:

user,passwd = 'alex','1234'

def auth(outh_type):
    print('auth func:',outh_type)
    def outh_wrapper(func):
        def wrapper(*args,**kwargs):
            print('wrapper func args:',*args,**kwargs)
            if outh_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)
                    print('-- after authentication')
                    return res
                else:
                    exit("\033[31;1mInvalid username or password\033[0m")
            elif outh_type == 'ldap':
                print('搞毛線')

        return wrapper
    return outh_wrapper

@auth(outh_type='local')
def index():
    print('welcom to index page')

index()

 http://www.cnblogs.com/wupeiqi/articles/4980620.html  

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM