1. 程式人生 > >day13 迭代器和生成器

day13 迭代器和生成器

1複習

# 函式 —— 2天
    # 函式的定義和呼叫
    # def 函式名(形參):
        #函式體
        #return 返回值  #被呼叫的地方接收
    #呼叫 函式名(實參)
    # 站在形參的角度上 : 位置引數,*args,預設引數(陷阱),**kwargs
    # 站在實參的角度上 : 按照位置傳,按照關鍵字傳
    # 返回值:沒有返回值 返回一個值 返回多個值
    # 接收返回值:沒有返回值不接收,返回一個值用一個變數接收,返回多個值用一個變數或者對應數目的變數接收
# 閉包函式 —— 在內部函式引用外部函式的變數
# 裝飾器函式—— 裝飾器一定是閉包函式
# 裝飾器的作用 : 在不改變原來函式的呼叫方式的情況下 在這個函式的前後新增新的功能 # 完美的符合了一個開發原則 :開放封閉原則 # 對擴充套件是開發的 # 對修改是封閉的 # 基礎的裝飾器 # from functools import wraps # def wrapper(func): # @wraps(func) # def inner(*args,**kwargs): # '''在函式被呼叫之前新增的程式碼'''
# ret = func(*args,**kwargs) # func是被裝飾的函式 在這裡被呼叫 # '''在函式被呼叫之後新增的程式碼''' # return ret # return inner # 使用 —— @wrapper # @wrapper # def func(): #inner # pass # # func.__name__ # 帶引數的裝飾器
# @wrapper -- > @warapper(argument) # 三層巢狀函式 # def outer(形參): # def wrapper(func): # def inner(*args,**kwargs): # '''在函式被呼叫之前新增的程式碼''' # ret = func(*args,**kwargs) # func是被裝飾的函式 在這裡被呼叫 # '''在函式被呼叫之後新增的程式碼''' # return ret # return inner # return wrapper # @outer(True) # def func(): # pass # 多個裝飾器裝飾一個函式 # 俄羅斯套娃 #def wrapper1(func): # @wraps(func) # def inner(*args,**kwargs): # print('before 1') # print('******') # ret = func(*args,**kwargs) # func是被裝飾的函式 在這裡被呼叫 # '''在函式被呼叫之後新增的程式碼''' # return ret # def wrapper2(func): # @wraps(func) # def inner(*args,**kwargs): # print('before 2') # ret = func(*args,**kwargs) # func是被裝飾的函式 在這裡被呼叫 # '''在函式被呼叫之後新增的程式碼''' # return ret # @wrapper1 # @wrapper2 # def func(): # print('111') # 迭代器和生成器 —— 兩天 # 內建函式 —— 兩天

2迭代器

1雙下方法

#雙下方法
print([1].__add__([2]))
print([1]+[2])
<<<
[1, 2]
[1, 2]
#list dic str set tuple range enumerate
print(dir([])) #告訴我列表的所有方法
ret=set(dir([]))&set(dir({}))&set(dir(""))&set(dir(range(12)))
print(ret)
print(set(dir([]))-set(dir({})))
<<<
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
{'__gt__', '__reduce_ex__', '__doc__', '__getitem__', '__len__', '__sizeof__', '__new__', '__eq__', '__delattr__', '__str__', '__reduce__', '__format__', '__repr__', '__ne__', '__le__', '__lt__', '__iter__', '__getattribute__', '__init__', '__contains__', '__subclasshook__', '__setattr__', '__dir__', '__class__', '__ge__', '__init_subclass__', '__hash__'}
{'__iadd__', '__imul__', '__mul__', 'count', 'index', 'sort', 'reverse', 'append', '__rmul__', 'extend', 'remove', 'insert', '__reversed__', '__add__'}
'''
可迭代協議: 
            
            只要能被for迴圈的資料型別 就一定有__iter__方法     []
            iterable 只要含有__iter__方法的都是可迭代的
迭代器協議: 
            一個列表執行了__iter__()之後的返回值就是一個迭代器 [].__iter__
            iteraor   內部含有__iter__和__next__方法的就是迭代器
            通過__next__()就可以從迭代器中一個一個取值 :print(iterator.__next__())
for:
for迴圈其實就是在使用迭代器
只有是可迭代物件的時候才能用for
當我們用一個新的變數 不確定能不能for迴圈的時候 就判斷是否可迭代
判斷方法 from _collections_abc import  
        Iterable print(isinstance([],Iterable))
        print('__iter__'in dir([])) '''

2協議

#協議
print([].__iter__())  #列印迭代器直接給你記憶體地址
print(set(dir([].__iter__()))-set(dir([]))) #列表迭代器相當於列表的獨特方法
print([1,'a','bbb'].__iter__().__length_hint__()) #__length_hint__求元素個數
l=[1,2,3]
iterator=l.__iter__()
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
<<<
<list_iterator object at 0x0000026048DF4438>
{'__setstate__', '__next__', '__length_hint__'}
3
1
2
3

3判斷方法

#判斷方法
print('__iter__'in dir([]))
print('__iter__'in dir([].__iter__()))
from _collections_abc import  Iterable  #棄用警告:不推薦使用或匯入來自collections
from collections.abc import  Iterator   #而不是“collections.abc”中的ABC
print(isinstance([],Iterator))          # 並且在python3.8中它將停止工作
print(isinstance([],Iterable)) #判斷[]是不是可迭代的
<<<
True
True
False
True

4for

#for
#只要有iter方法就能被迴圈  for迴圈其實就是在使用迭代器
l=[1,2,3]
for i in l.__iter__():
    print(i)
print([].__iter__()) #列印迭代器直接給你記憶體地址
print(range(10).__iter__())
print(range(10))

l=[1,2,3]
for i in l:
    print(i)
    if i ==2:
        break
<<<
1
2
3
<list_iterator object at 0x0000024B1E314208>
<range_iterator object at 0x0000024B1DFAD830>
range(0, 10)
1
2

5迭代器的好處

# 迭代器的好處
'''
從容器型別中一個個取值 會把所有值都取到
節省記憶體空間
    迭代器並不會在記憶體中佔一大塊記憶體
    而是隨著迴圈 每次生成一個next給我一個'''

l=[1,2,3,4]
iterator=l.__iter__()
while 1:
    print(iterator.__next__())
<<<
Traceback (most recent call last):
  File "C:/python全棧/me第一部分/day13 迭代器和生成器.py", line 76, in <module>
    print(iterator.__next__())
StopIteration
1
2
3
4
print(range(10000))
print(list(range(3)))
def f():
    for i in range(200):
        i="wahaha%s"%i
    return i
print(f())

<<<
range(0, 10000)
[0, 1, 2]
wahaha199

3.生成器

#3 生成器
#生成器函式 本質上就是我們自己寫的函式
#只要含有yield關鍵字的函式都是生成器函式
#yield不能和return共用且需要寫在函式內
def generetor():
    print(1)
    yield 'a'
ret=generetor()
print(ret)
print(ret.__next__())
<<<
<generator object generetor at 0x00000246FE4C8A98>
1
a

1.生成器函式 執行之後會得到一個生成器作為一個返回值

#生成器函式 執行之後會得到一個生成器作為一個返回值
def generetor1():
    print(1)
    yield 'a'
    print(2)
    yield 'b'
    yield 'c'
g=generetor1()
print(g)
ret=g.__next__()
print(ret)
# for i in g:
#     print(i)  1 a 2 b c
ret=g.__next__()
print(ret)
ret = g.__next__()
print(ret)

<<<
1
a
2
b
c

2.next方法獲取生成器的值

# 娃哈哈
import time
def wahaha():
    for i in range(200000):
        yield '娃哈哈%s'% i
g=wahaha()
g1=wahaha()
print(g.__next__())
print(g.__next__())
print(g1.__next__())

g=wahaha()
count=0
a=time.time()
for i in g:
    count+=1
    print(i)
    if count>3:
        break
b=time.time()
print(b-a)
print("***",g.__next__())
for i in g:
    count+=1
    print(i)
    if count>6:
        break
print("&&",g.__next__())
<<<
娃哈哈0
娃哈哈1
娃哈哈0
娃哈哈0
娃哈哈1
娃哈哈2
娃哈哈3
0.0
*** 娃哈哈4
娃哈哈5
娃哈哈6
娃哈哈7
&& 娃哈哈8

4 利用生成器監聽檔案輸入

#4 利用生成器監聽檔案輸入
def tail(filename):
    f=open(filename,encoding='utf-8')
    while True:
        line=f.readline()
        if line.strip():
            yield line.strip()  #使用生成器在後面的操作中更靈活想加*就加
g=tail('file')
# print(g.__next__())
for i in g:
    if 'python' in i:
        print("***",i)
<<<
*** python