python三大器


裝飾器

裝飾器的作用:

  • 裝飾器的本質:一個閉包函數 (高階函數+嵌套函數)
  • 裝飾器的功能:在不修改原函數及其調用方式的情況下對原函數功能進行擴展

閉包原理

 

 

裝飾器執行流程

 

帶多個參數函數

import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func2 = timer(func2)
def func2(a):
    print('in func2 and get a:%s'%(a))
    return 'fun2 over'

func2('aaaaaa')
print(func2('aaaaaa'))

 

正常我們情況下查看函數的一些信息的方法在此處都會失效

def index():
    '''這是一個主頁信息'''
    print('from index')

print(index.__doc__)    #查看函數注釋的方法
print(index.__name__)   #查看函數名的方法

 

functools的應用

  • functools的wraps能夠將原有的函數名返回
from functools import wraps

def deco(func):
    @wraps(func) #加在最內層函數正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

@deco
def index():
    '''哈哈哈哈'''
    print('from index')

print(index.__doc__)
print(index.__name__)

 

給裝飾器帶參數

def outer(flag):
    def timer(func):
        def inner(*args,**kwargs):
            if flag:
                print('''執行函數之前要做的''')
            re = func(*args,**kwargs)
            if flag:
                print('''執行函數之后要做的''')
            return re
        return inner
    return timer

@outer(False)
def func():
    print(111)
func()

 

迭代器

迭代和可迭代協議

可以被for循環的都是可迭代的

 字符串、列表、元組、字典、集合都可以被for循環,說明他們都是可迭代的

 證明:

from collections import Iterable
                             
l = [1,2,3,4]                
t = (1,2,3,4)                
d = {1:2,3:4}                
s = {1,2,3,4}                
                             
print(isinstance(l,Iterable))
print(isinstance(t,Iterable))
print(isinstance(d,Iterable))
print(isinstance(s,Iterable))

結合我們使用for循環取值的現象,再從字面上理解一下,其實迭代就是我們剛剛說的,可以將某個數據集內的數據“一個挨着一個的取出來”,就叫做迭代

可迭代協議

從結果分析原因,能被for循環的就是“可迭代的”,但是for怎么知道誰是可迭代的呢?

假如我們自己寫了一個數據類型,希望這個數據類型里的東西也可以使用for被一個一個的取出來,那我們就必須滿足for的要求。這個要求就叫做“協議”。

可以被迭代要滿足的要求就叫做可迭代協議。可迭代協議的定義非常簡單,就是內部實現了__iter__方法。

接下來我們就來驗證一下:

print(dir([1,2]))
print(dir((2,3)))
print(dir({1:2}))
print(dir({1,2}))

[.....__iter__.....]
[.....__iter__.....]
[.....__iter__.....]
[.....__iter__.....]

可以被for循環的都是可迭代的,要想可迭代,內部必須有一個__iter__方法.

 

迭代器協議

'''
dir([1,2].__iter__())是列表迭代器中實現的所有方法,dir([1,2])是列表中實現的所有方法,都是以列表的形式返回給我們的,為了看的更清楚,我們分別把他們轉換成集合,
然后取差集。
'''
#print(dir([1,2].__iter__()))
#print(dir([1,2]))
print(set(dir([1,2].__iter__()))-set(dir([1,2])))

結果:
{'__length_hint__', '__next__', '__setstate__'}
iter_l = [1,2,3,4,5,6].__iter__()
#獲取迭代器中元素的長度
print(iter_l.__length_hint__())
#根據索引值指定從哪里開始迭代
print('*',iter_l.__setstate__(4))
#一個一個的取值
print('**',iter_l.__next__())
print('***',iter_l.__next__())

在for循環中,就是在內部調用了__next__方法才能取到一個一個的值

 

用迭代器的next方法的遍歷。

l = [1,2,3,4]
l_iter = l.__iter__()
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
item = l_iter.__next__()
print(item)
  • 但是一旦超出了迭代的范圍就會報錯(StopIteration)告訴我們里面沒有元素了
  • for循環內部幫助我們捕捉了異常

迭代器遵循迭代器協議:必須擁有__iter__方法和__next__方法。

  • for循環就是基於迭代器協議提供了一個統一的可以遍歷所有對象的方法
  • 即在遍歷之前,先調用對象的__iter__方法將其轉換成一個迭代器
  • 使用迭代器協議去實現循環訪問(__next__)方法
  • 這樣所有的對象就都可以通過for循環來遍歷了

 

生成器

什么是生成器

我們知道的迭代器有兩種:一種是調用方法直接返回的,一種是可迭代對象通過執行iter方法得到的,迭代器有的好處是可以節省內存。

如果在某些情況下,我們也需要節省內存,就只能自己寫。我們自己寫的這個能實現迭代器功能的東西就叫生成器。

 

Python中提供的生成器:

1.生成器函數:常規函數定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,以便下次重它離開的地方繼續執行

2.生成器表達式:類似於列表推導,但是,生成器返回按需產生結果的一個對象,而不是一次構建一個結果列表

 

生成器Generator:

  本質:迭代器(所以自帶了__iter__方法和__next__方法,不需要我們去實現)

  特點:惰性運算,開發者自定義

生成器函數

一個包含yield關鍵字的函數就是一個生成器函數。

yield可以為我們從函數中返回值,但是yield又不同於return,return的執行意味着程序的結束,調用生成器函數不會得到返回的具體的值,而是得到一個可迭代的對象。

每一次獲取這個可迭代對象的值,就能推動函數的執行,獲取新的返回值。直到函數執行結束。

import time
def genrator_fun1():
    a = 1
    print('現在定義了a變量')
    yield a
    b = 2
    print('現在又定義了b變量')
    yield b

g1 = genrator_fun1()
print('g1 : ',g1)       #打印g1可以發現g1就是一個生成器
print('-'*20)   #我是華麗的分割線
print(next(g1))
time.sleep(1)   #sleep一秒看清執行過程
print(next(g1))

send:

def generator():
    print(123)
    content = yield 1
    print('=======',content)
    print(456)
    yield2

g = generator()
ret = g.__next__()
print('***',ret)
ret = g.send('hello')   #send的效果和next一樣
print('***',ret)

#send 獲取下一個值的效果和next基本一致
#只是在獲取下一個值的時候,給上一yield的位置傳遞一個數據
#使用send的注意事項
    # 第一次使用生成器的時候 是用next獲取下一個值
    # 最后一個yield不能接受外部的值

生成器表達式

把列表解析的[]換成()得到的就是生成器表達式

ret=(x ** 2 for x in range(4))

 

生成器總結

  • 列表解析與生成器表達式都是一種便利的編程方式,只不過生成器表達式更節省內存
  • Python不但使用迭代器協議,讓for循環變得更加通用。大部分內置函數,也是使用迭代器協議訪問對象的。例如, sum函數是Python的內置函數,該函數使用迭代器協議訪問對象,而生成器實現了迭代器協議,所以,我們可以直接這樣計算一系列值的和:
    sum(x ** 2 for x in range(4))

     

生成器面試題

def add(n,i):
    return n+i

def test():
    for i in range(4):
        yield i

g=test()
for n in [1,10]:
    g=(add(n,i) for i in g)

print(list(g))

 

迭代器生成器總結

可迭代對象:

  擁有__iter__方法

  特點:惰性運算

  例如:range(),str,list,tuple,dict,set

迭代器Iterator:

  擁有__iter__方法和__next__方法

  例如:iter(range()),iter(str),iter(list),iter(tuple),iter(dict),iter(set),reversed(list_o),map(func,list_o),filter(func,list_o),file_o

生成器Generator:

  本質:迭代器,所以擁有__iter__方法和__next__方法

  特點:惰性運算,開發者自定義

迭代器和生成器
    -迭代器
        -可迭代協議--含有iter方法的都可以迭代的
        -迭代器協議--含有next和iter的都是迭代器
        特點:
            -節省內存空間
            -方便逐個取值,一個迭代器只能取一次
    -生成器 
        所有的生成器都是迭代器
        -含有yield 關鍵字的函數都是生成器函數
        -生成器函數特點:
            -調用之后函數內的代碼不執行,返回生成器
            -每從生成器中取一個值就會執行一段代碼,遇見yield就停止
            如何從生成器中取值?
                -for : 如果沒有break會一直取完
                -next : 每次只取一次
                -send: 不能用在一第一個,取下一個值的時候給上一個位置傳一個新的值
                - 數據類型強制轉換:會一次性把所有的數據都讀到內存中
        生成器表達式:
            (條件成立想放在生成器中的值 for i in 可迭代的 if 條件)

 

轉自http://www.cnblogs.com/Eva-J/articles/7213953.html

 


免責聲明!

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



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