1. 程式人生 > >Python - 三大器 叠代器,生層器,裝飾器

Python - 三大器 叠代器,生層器,裝飾器

mat ear __iter__ 對象類型 try 生成 -- diedai 表達式

目錄

  • Python - 三大器 叠代器,生層器,裝飾器
    • 一. 容器
    • 二. 可叠代對象(iterable)
    • 三. 叠代器
    • 四. 生成器
    • 五. 裝飾器
      • 1. 定義
    • 六. 閉包

Python - 三大器 叠代器,生層器,裝飾器

在介紹三大器之前先來了解一下容器和可叠代對象...

一. 容器

容器是一種把多個元素組織在一起的數據結構,容器中的元素可以逐個地叠代獲取,可以用in, not in關鍵字判斷元素是否包含在容器中。通常這類數據結構把所有的元素存儲在內存中(也有一些特例,並不是所有的元素都放在內存,比如叠代器和生成器對象)在Python中,常見的容器對象有:

  • list, deque...
  • set, frozensets(不可變集合)...
  • dict, defaultdict, OrderedDict, Counter...
  • tuple, namedtuple...
  • str

容器的概念就像一個盒子,可以往裏面裝東西.當它可以用來詢問某個元素是否包含在其中時,那麽這個對象就可以認為是一個容器,比如 list,set,tuples都是容器對象:

>>> assert 1 in [1, 2, 3]      # lists
>>> assert 4 not in [1, 2, 3]
>>> assert 1 in {1, 2, 3}      # sets
>>> assert 4 not in {1, 2, 3}
>>> assert 1 in (1, 2, 3)      # tuples
>>> assert 4 not in (1, 2, 3)

詢問某元素是否在dict中用dict的中key:

>>> d = {1: 'foo', 2: 'bar', 3: 'qux'}
>>> assert 1 in d
>>> assert 'foo' not in d  # 'foo' 不是dict中的元素

詢問某substring是否在string中:

>>> s = 'foobar'
>>> assert 'b' in s
>>> assert 'x' not in s
>>> assert 'foo' in s

盡管絕大多數容器都提供了某種方式來獲取其中的每一個元素,但這並不是容器本身提供的能力,而是可叠代對象賦予了容器這種能力,當然並不是所有的容器都是可叠代的,比如:Bloom filter,雖然Bloom filter可以用來檢測某個元素是否包含在容器中,但是並不能從容器中獲取其中的每一個值,因為Bloom filter壓根就沒把元素存儲在容器中,而是通過一個散列函數映射成一個值保存在數組中。

二. 可叠代對象(iterable)

大部分對象都是可叠代,只要實現了__iter__方法的對象就是可叠代的。
__iter__方法會返回叠代器(iterator)本身,例如:

>>> lst = [1,2,3]
>>> lst.__iter__()
<listiterator object at 0x7f97c549aa50>

Python提供一些語句和關鍵字用於訪問可叠代對象的元素,比如for循環、列表解析、邏輯操作符等。

判斷一個對象是否是可叠代對象:

>>> from collections import Iterable  # 只導入Iterable方法
>>> isinstance('abc', Iterable)     
True
>>> isinstance(1, Iterable)     
False
>>> isinstance([], Iterable)
True

這裏的isinstance()函數用於判斷對象類型。
可叠代對象一般都用for循環遍歷元素,也就是能用for循環的對象都可稱為可叠代對象。
例如,遍歷列表:

>>> lst = [1, 2, 3]
>>> for i in lst:
...   print i
...

三. 叠代器

叠代器協議是指:對象必須提供一個next方法,執行該方法要麽返回叠代中的下一項,要麽就引起一個Stoplteration異常,以終止叠代(只能往後走不能往前退)

實現了叠代器協議的對象(對象內部定義了一個__iter__()方法)

python中的內部工具(如for循環,sum,min,max函數等)基於叠代器協議訪問對象。

使用叠代器的好處:

1)如果使用列表,計算值時會一次獲取所有值,那麽就會占用更多的內存。而叠代器則是一個接一個計算。

2)使代碼更通用、更簡單。

判斷是否是叠代器:

>>> from collections import Iterator
>>> isinstance(d, Iterator)
False
>>> isinstance(d.iteritems(), Iterator)
True

使用next方法:

>>> iter_items = d.iteritems()
>>> iter_items.next()
('a', 1)
>>> iter_items.next()
('c', 3)
>>> iter_items.next()
('b', 2)

叠代器的原理:

1 #基於叠代器協議
 2 li = [1,2,3]
 3 diedai_l = li.__iter__()
 4 print(diedai_l.__next__())
 5 print(diedai_l.__next__())
 6 print(diedai_l.__next__())
 7 # print(diedai_l.__next__())  # 超出邊界報錯
 8 
 9 #下標
10 print(li[0])
11 print(li[1])
12 print(li[2])
13 # print(li[3]) # 超出邊境報錯
14 
15 # 用while循環模擬for循環機制
16 diedai_l = li.__iter__()
17 while True:
18     try:
19         print(diedai_l.__next__())
20     except StopIteration:
21         print("叠代完畢,循環終止")
22         break
23 
24 # for循環訪問方式
25 # for循環本質就是遵循叠代器協議的訪問方式,先調用diedai_l=li.__iter__方法
26 # 或者直接diedai_l=iter(l),然後依次執行diedai_l.__next__(),直到捕捉到
27 # StopItearation終止循環
28 # for循環所有的對象的本質都是一樣的原理

四. 生成器

可以理解為一種數據類型,自動實現叠代器協議

  在調用生成器運行的過程中,每次遇到yield時函數會暫停並保存當前所有的運行信息,返回yield的值。並在下一次執行next()方法時從當前位置繼續運行

  1. 表現形式:

    生成器函數 帶yield的函數(1、返回值 2、保留函數的運行狀態)

          next(t)  t.__next__  t.send(可以給上一層的yield傳值)

     # 用生成器函數
     # yield 相當於return控制的是函數的返回值
     # x=yield的另外一個特性,接收send傳過來的值,賦值給x
     def test():
         print("開始啦")
         first = yield # return 1   first = None
         print("第一次",first)
         yield 2
         print("第二次")
     t = test()
     print(test().__next__())
     res = t.__next__() # next(t)
     print(res)
     res = t.send("函數停留在first那個位置,我就是給first賦值的")
     print(res)
    
     輸出結果
     開始啦
     None
     開始啦
     None
     第一次 函數停留在first那個位置,我就是給first賦值的
  2. 生成器表達式

    print(sum(i for i in range(10000))) # 表達式一般用for循環 (i for i in range(10000))
    # 作用 節省內存,在內部已經實現了__iter__的方法

五. 裝飾器

1. 定義

在不修改被修飾函數的源代碼和調用方式的情況下給其添加額外功能.

裝飾器 = 高階函數+函數嵌套+閉包

import time #導入時間模塊

def foo(func):  # func = test
    def bar(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)   # 這裏就是在運行test()  賦予變量
        stop_time = time.tiem()
        print("一場LOL時間為{}").format(stop_time-start_time)
        return res  # 返回test()的值
    return bar

def test(name, age):
    time.sleep(1)
    print("哈哈")
    return "heihei"

res = test("德瑪西亞", age=10)
print(ret)

六. 閉包

根據這句話,其實我們自己就可以總結出在python語言中形成閉包的三個條件,缺一不可:

1)必須有一個內嵌函數(函數裏定義的函數)——這對應函數之間的嵌套

2)內嵌函數必須引用一個定義在閉合範圍內(外部函數裏)的變量——內部函數引用外部變量

3)外部函數必須返回內嵌函數——必須返回那個內部函數

def funx():
x=5
def funy():
    nonlocal x
    x+=1
    return x
return funy

python閉包的優點:

避免使用全局變量

可以提供部分數據的隱藏

可以提供更優雅的面向對象實現

Python - 三大器 叠代器,生層器,裝飾器