python函數(5):迭代器和生成器

来源:http://www.cnblogs.com/liluning/archive/2017/08/02/7274862.html
-Advertisement-
Play Games

迭代器和生成器是函數中的一大重點,務必掌握,何為迭代?何為迭代器? ...


迭代器和生成器是函數中的一大重點,務必掌握,何為迭代?何為迭代器?

預習:

1、處理文件,用戶指定要查找的文件和內容,將文件中包含要查找內容的每一行都輸出到屏幕(使用生成器)

2、批量處理文件,用戶指定要查找的目錄和內容,將本層目錄下所有文件中包含要查找內容的每一行都輸出到屏幕

 

一、迭代器

for i in 50:
    print(i)
#運行結果:
# Traceback (most recent call last):
#   File "G:/python/python代碼/八月/day2 迭代器生成器/3迭代器.py", line 8, in <module>
#     for i in 50:
# TypeError: 'int' object is not iterable

報錯:

TypeError: 'int' object is not iterable

類型報錯:'int'對象是不可迭代的    何為迭代?

iterable:可迭代的;迭代的;

可迭代的:從上面代碼可以簡單分析出能被for迴圈取值的就是可迭代,那麼我們就可以初步總結出可迭代的類型:str、list、tuple、set、dict

可迭代的 ——對應的標誌 擁有__iter__方法

print('__iter__' in dir([1,2,3]))  #判斷一個變數是不是一個可迭代的

可迭代協議

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


 

二、迭代器

__iter__方法作用:

l = [1,2,3,4,5]
print(l.__iter__())
l_iterator = iter(l)  #建議用iter(l)
print(set(dir(l_iterator))-set(dir(l)))
#結果:
#<list_iterator object at 0x000001FDD1B79048>
#{'__length_hint__', '__next__', '__setstate__'}
迭代器

iterator:迭代器;迭代程式

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

通過iter(x)得到的結果就是一個迭代器,

x是一個可迭代的對象

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

__next__的精髓:

l = [1,2,3,4,5]
l_iterator = iter(l)
print(l_iterator.__next__())
print(l_iterator.__next__())
print(l_iterator.__next__())
print(l_iterator.__next__())
print(l_iterator.__next__())
next(l_iterator) #==l_iterator.__next__()
while True:
    try:
        print(next(l_iterator))
    except StopIteration:
        break
__next__方法的使用精髓

如果我們一直取next取到迭代器里已經沒有元素了,就會報錯(拋出一個異常StopIteration),告訴我們,列表中已經沒有有效的元素了。這個時候,我們就要使用異常處理機制來把這個異常處理掉。try_except異常處理機制只做瞭解,不是本章重點,會面會詳細講解。

判斷是否可迭代和迭代器的簡潔方法:

from collections import Iterable
from collections import Iterator
s = 'abc'
print(isinstance(s,Iterable))
print(isinstance(s,Iterator))
print(isinstance(iter(s),Iterator))
判斷可迭代和迭代器

不管是一個迭代器還是一個可迭代對象,都可以使用for迴圈遍歷

迭代器出現的原因 幫你節省記憶體


 

三、生成器

迭代器大部分都是在python的內部去使用的,我們直接拿來用就行了

我們自己寫的能實現迭代器功能的東西就叫生成器。

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

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

生成器Generator:

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

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

#生成器函數
def func():
    print('aaaa')
    a = 1
    yield a    #返回第一個值
    print('bbbb')
    yield 12   #返回第二個值

ret = func()  #拿到一個生成器
# print(ret) #<generator object func at 0x0000028AE2DA2EB8>
print(next(ret)) #取第一個值
print(next(ret)) #取第二個值
print(next(ret)) #取第三個值 會報錯 因為沒有第三個值


def make_cloth():
    for i in range(2000000):
        yield "第%s件衣服"%i

szq = make_cloth()
print(next(szq))
print(next(szq))

print(next(szq))
for i in range(50):
    print(next(szq))
生成器函數

生成器的好處:不會一下子在記憶體中生成太多數據

其它應用:

import time


def tail(filename):
    f = open(filename)
    f.seek(0, 2) #從文件末尾算起
    while True:
        line = f.readline()  # 讀取文件中新的文本行
        if not line:
            time.sleep(0.1)
            continue
        yield line

tail_g = tail('tmp')
for line in tail_g:
    print(line)
生成器監聽文件輸入的例子
def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        term = yield average
        total += term
        count += 1
        average = total/count


g_avg = averager()
next(g_avg)
print(g_avg.send(10))
print(g_avg.send(30))
print(g_avg.send(5))
計算移動平均值簡單
def init(func):  #在調用被裝飾生成器函數的時候首先用next激活生成器
    def inner(*args,**kwargs):
        g = func(*args,**kwargs)
        next(g)
        return g
    return inner

@init
def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        term = yield average
        total += term
        count += 1
        average = total/count


g_avg = averager()
# next(g_avg)   在裝飾器中執行了next方法
print(g_avg.send(10))
print(g_avg.send(30))
print(g_avg.send(5))
計算移動平均值升級_生成器激活裝飾器
def func():
    # for i in 'AB':
    #     yield i
    yield from 'AB'  #等同於上面兩行
    yield from [1,2,3]
g = func()
print(next(g))
print(next(g))
print(next(g))
print(next(g))
yield from

 

四、列表推導式和生成器表達式

for i in range(100):
    print(i*i)

l =[i*i for i in range(100)]   #列表推導式
print(l)

l = [{'name':'v','age':28},{'name':'v'}]   
name_list = [dic['name'] for dic in l]    #列表推導式
print(name_list)

l = [{'name':'v1','age':28},{'name':'v2'}]
name_list_generator = (dic['name'] for dic in l)    #生成器表達式
print(name_list_generator)
print(next(name_list_generator))
print(next(name_list_generator))

egg_list=['雞蛋%s' %i for i in range(10)]    #列表推導式
print(egg_list)

laomuji = ('雞蛋%s' %i for i in range(1,11))    #生成器表達式
print(laomuji)
print(next(laomuji))
print(next(laomuji))
列表推導式和生成器表達式

使用生成器的優點:

1、延遲計算,一次返回一個結果。也就是說,它不會一次生成所有的結果,這對於大數據量處理,將會非常有用。

2、提高代碼可讀性

#列表解析
sum([i for i in range(100000000)])#記憶體占用大,機器容易卡死
 
#生成器表達式
sum(i for i in range(100000000))#幾乎不占記憶體

總結:

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

2、列表解析與生成器表達式都是一種便利的編程方式,只不過生成器表達式更節省記憶體

3、Python不但使用迭代器協議,讓for迴圈變得更加通用。大部分內置函數,也是使用迭代器協議訪問對象的。例如, sum函數是Python的內置函數,該函數使用迭代器協議訪問對象,而生成器實現了迭代器協議,所以,我們可以直接這樣計算一系列值的和

print(sum([1,2,3]))
print(sum(range(1,4)))
print(sum(x ** 2 for x in range(4)))
print(sum([x ** 2 for x in range(4)]))

 

思維導圖:

預習答案:

def grep_file(filename,grep_content):
    f = open(filename)
    for line in f:
        if grep_content in line:
            yield line

g = grep_file('tmp_file','python')
for line in g:
    print(line,end='')
普通青年版(1題)
def init(func):
    def inner(*args,**kwargs):
        g = func(*args,**kwargs)
        next(g)
        return g
    return inner

@init   #grep_file = init(grep_file)
def grep_file(grep_content,printer_g):
    while True:
        filename  = yield
        f = open(filename)
        for line in f:
            if grep_content in line:
                printer_g.send(line)

@init  ##printer = init(printer) 激活print_g
def printer():
    while True:
        line = yield
        if line:print(line,end='')

grep_g = grep_file('python', printer())
grep_g.send('tmp_file')
妖孽青年版(1題)
import os
def getpath(filepath):
    g = os.walk(filepath)
    for par_dir, _, files in g:
        for file in files:
            yield par_dir + "\\" + file

# 2打開文件對象發給3
def getfile(filepaths):
    for filepath in filepaths:
        with open(filepath, encoding="utf-8") as file:
            yield file

# 3讀取每一行發給4
def getline(files):
    for file in files:
        for line in file:
            yield line

# 4判斷pattern發給5
def grep(lines, pattern):
    for line in lines:
        if pattern in line:
            yield line

# 5列印文件名
def printname(strings):
    for string in strings:
        print(string)

filepath = r"F:\Code\Python\LearnPython\Day14 generator"
pattern = "jean"

printname(grep(getline(getfile(getpath(filepath))), pattern))
妖孽升級版(2題)

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、下載solr6.6 並解壓 地址: http://www.apache.org/dyn/closer.lua/lucene/solr/6.6.0 2、安裝JDK1.8 地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8 ...
  • 1 //選擇排序對數據進行升序排序 2 public static void selectSortArray(int[] arr){ 3 for(int i = 0; iarr[j]){ 6 int temp = arr[j]; 7 arr[j... ...
  • 裝箱和拆箱 裝箱和拆箱 基本數據類型的包裝類 舉兩個例子,看一下 基本數據類型的包裝類 舉兩個例子,看一下 對於byte/short/long/float/double和Integer(int)類用法類似 對於byte/short/long/float/double和Integer(int)類用法類 ...
  • 有時候,需要禁止函數修改列表。例如要對裂變進行修改操作,也要保留原來的未列印的設計列表,以供備案。為解決這個問題,可向函數傳遞列表的副本而不是原件;這樣函數所做的任何修改都隻影響副本,而絲毫不影響原件。 8-9 魔術師 魔術師 :創建一個包含魔術師名字的列表,並將其傳遞給一個名為show_magic ...
  • 垃圾收集器與記憶體分配策略 由於JVM中對象的頻繁操作是在堆中,所以主要回收的是堆記憶體,方法區中的回收也有,但是比較謹慎 一、對象死亡判斷方法 1.引用計數法 就是如果對象被引用一次,就給計數器+1,否則-1 實現簡單,但是無法解決對象相互引用的問題;實際上JVM也不是使用的此種方式,因此已下的程式我 ...
  • 最近跑來打數據結構,於是我決定搞一發可持久化,然後發現……一發不可收啊…… 對於可持久化數據結構,其最大的特征是“歷史版本查詢”,即可以回到某一次修改之前的狀態,並繼續操作;而這種“歷史版本查詢”會衍生出其他一些強大的操作。 今天,我們主要講解可持久化線段樹。其實,它的另外一個名字“主席樹”似乎更加 ...
  • 1. php中字元串可以用哪三種方法定義: 單引號、雙引號、定界符 2. 定義常量和靜態常量的語法是: define(‘常量名’,’常量值’) static $var 3. 用php列印出昨天的時間,格式是2006-05-10 22:21:21: date_default_timezone_set( ...
  • 最近接觸了不少次下載http網頁和文件的程式,突然對其原理很感興趣,又碰巧看到了http協議基於socket,這更是讓我激動不已。畢竟之前花了很長時間接觸socket這個實用的底層協議,做了小型聊天室來練習,然而卻不知道生活中有什麼具體的實例是由socket完成的。於是乎,查閱了各路筆記和文檔,再加... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...