Python迭代和解析(4):自定義迭代器

来源:https://www.cnblogs.com/f-ck-need-u/archive/2019/01/13/10263299.html
-Advertisement-
Play Games

本文介紹如何自定義迭代器,涉及到類的運算符重載,包括 的索引迭代,以及 、`__next__ __contains__`,如果不瞭解這些知識可跳過本文。 索引迭代方式 索引取值和分片取值 元組、列表、字典、集合、字元串都支持索引取值操作和分片操作。 分片操作實際上將一個slice對象當作索引位傳遞給 ...


解析、迭代和生成系列文章:https://www.cnblogs.com/f-ck-need-u/p/9832640.html


本文介紹如何自定義迭代器,涉及到類的運算符重載,包括__getitem__的索引迭代,以及__iter____next____contains__,如果不瞭解這些知識可跳過本文。

索引迭代方式

索引取值和分片取值

元組、列表、字典、集合、字元串都支持索引取值操作和分片操作。

>>> L = [11,21,31,41]
>>> L[0]
11
>>> L[0:2]
[11, 21]

分片操作實際上將一個slice對象當作索引位傳遞給序列,然後以索引取值的方式取得所需元素。

>>> L[0:2]
[11, 21]

>>> L[slice(0,2)]
[11, 21]

slice對象由slice()函數創建,它有3個參數:起始索引位、結束索引位、步進值。例如:

>>> slice(0,2)
slice(0, 2, None)

__getitem__

列表、元組等序列之所以可以索引取值、分片取值,是因為它們實現了__getitem__方法。

例如:

>>> hasattr(list,"__getitem__")
True
>>> hasattr(tuple,"__getitem__")
True
>>> hasattr(dict,"__getitem__")
True
>>> hasattr(str,"__getitem__")
True

如果自定義類並實現__getitem__方法,它們會重載索引取值:

class cls:
  def __getitem__(self, index):
    print("getitem index", index)
    return index * 2

>>> c = cls()
>>> c[1]
getitem index 1
2
>>> c[2]
getitem index 2
4
>>> c[3]
getitem index 3
6

上面的自定義類只支持索引取值,不支持分片取值。因為__getitem__中沒有編寫索引取值的方式,也就不支持傳遞slice對象來進行分片取值。

分片和__getitem__

如果想要__getitem__支持分片取值,需要在__getitem__中使用索引取值的方式,以便支持slice對象作為索引。

下麵是一個簡單的支持分片操作的自定義類:

class cls:
  def __init__(self,data):
    self._data = data
  def __getitem__(self,index):
    print("getitem:",index)
    return self._data[index]

>>> c = cls([1,2,3,4])
>>> c[1]
getitem: 1
2
>>> c[0:2]
getitem: slice(0, 2, None)
[1, 2]

__setitem__和__delitem__

如果想要索引或者分片賦值,那麼會調用__setitem__()方法,如果想要刪除索引值或分片值,會調用__delitem__()方法。

class cls:
  def __init__(self,data):
    self._data = data
  def __getitem__(self,index):
    print("in getitem")
    return self._data[index]
  def __setitem__(self,index,value):
    print("in setitem")
    self._data[index] = value
  def __delitem__(self,index):
    print("in delitem")
    del self._data[index]
  def __repr__(self):
    return str(self._data)

>>> c = cls([11,22,33,44,55])
>>> c[1:3]
in getitem
[22, 33]
>>> c[1:3] = [222,333]
in setitem
>>> c
[11, 222, 333, 44, 55]
>>> del c[1:3]
in delitem

__getitem__索引迭代

__getitem__重載了索引取值和分片操作,實際上它也能重載索引的迭代操作。以for為例,它會迴圈獲取一個個的索引並向後偏移,直到超出索引邊界拋出IndexError異常而停止。

此外,__getitem__重載使得它可以被迭代,也就是它通過數值索引的方式讓這個對象變成可迭代對象,所有迭代工具(比如zip/map/for/in)都可以對這個對象進行迭代操作。

class cls:
  def __init__(self,data):
    self._data = data
  def __getitem__(self,index):
    return self._data[index]
  def __repr__(self):
    return str(self._data)

>>> c1 = cls([11,22,33,44,55])
>>> I = iter(c1)
>>> next(I)
11
>>> 22 in I
True

>>> I=iter(c1)
>>> for i in I:print(i,end=" ")
...
11 22 33 44 55

可迭代對象:__iter____next__

定以了__getitem__的類是可迭代的類型,是通過數值索引的方式進行迭代的,但這是退而求其次的行為,更好的方式是定義__iter__方法,使用迭代協議進行迭代。當同時定義了__iter____getitem__的時候,iter()函數優先選擇__iter__,只有在__iter__不存在的時候才會選擇__getitem__

例如:

class Squares:
    def __init__(self, start, stop):  # 迭代起始、終止位
        self.value = start
        self.stop = stop

    def __iter__(self):     # 返回自身的迭代器
        return self

    def __next__(self):     # 返回下一個元素
        if self.value > self.stop:   # 結尾時拋出異常
            raise (StopIteration)
        item = self.value**2
        self.value += 1
        return item

if __name__ == "__main__":
    for i in Squares(1, 5):
        print(i, end=" ")

    s = Squares(1,5)
    print()
    print(9 in s)

運行結果:

1 4 9 16 25
True

因為上面的類中同時定義了__iter____next__,且__iter__返回的是自身,所以這個類型的每個迭代對象都是單迭代的。

>>> s = Squares(1,5)
>>> I1 = iter(s)   # I1和I2迭代的是同一個對象
>>> I2 = iter(s)
>>> next(I1)
1
>>> next(I2)   # 繼續從前面的位置迭代
4
>>> next(I1)
9

自定義多迭代類型

要定義多迭代的類型,要求__iter__返回一個新的迭代對象,而不是self自身,也就是說不要返回自身的迭代器。

例如:

# 返回多個獨立的可迭代對象
class MultiIterator:
    def __init__(self, wrapped):
        self.wrapped = wrapped   # 封裝將被迭代的對象

    def __iter__(self):
        return Next(self.wrapped) # 返回獨立的可迭代對象

# 自身的迭代器
class Next:
    def __init__(self, wrapped):
        self.wrapped = wrapped
        self.offset = 0

    def __iter__(self):
        return self

    def __next__(self):   # 返回下一個元素
        if self.offset >= len(self.wrapped):
            raise (StopIteration)
        else:
            item = self.wrapped[self.offset]
            self.offset += 1
            return item    # 返回指定索引位置處的元素


if __name__ == "__main__":
    string = "abc"
    s = MultiIterator(string)
    for x in s:
        for y in s:
            print(x + y, end=" ")

每個for迭代工具都會先調用iter()來獲取可迭代對象,然後調用next()獲取下一個元素。而這裡的iter()會調用MultiIterator的__iter__來獲取可迭代對象,而MultiIterator所返回的可迭代對象是相互獨立的Next對象,因此for x in xfor y in s所迭代的是不同迭代對象,它們都有記錄著自己的迭代位置信息。


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

-Advertisement-
Play Games
更多相關文章
  • jdk8 foreach創建對象優化 lambda foreach 創建對象 @Async public void asyncFullEsDoc() { List<Integer> docIdList = Arrays.asList(913,914); if (CollectionUtil.isNo ...
  • 背景 Elasticsearch 不像關係型資料庫,沒有簡易的 SQL 用來查詢數據,只能通過調用 RESTful API 實現查詢。大體上查詢分為兩種,基於 URL 的和基於請求主體的。基於 URL 的方式比較簡單清晰,用得較多,在這簡單記錄下。 基本模式 基於 URL 的搜索請求基本模式如上圖所 ...
  • 看完上圖你是什麼反應?會罵人嗎?會就對了……,代碼整潔之道,是一條很漫長的路,註釋是其中一部分。 ...
  • Exercise2是註釋和井號 Comments and Pound Characters 具體詳情請參考 "習題一" ,這裡就不在做過多的贅述。 習題 3: 數字和數學計算 學習目標: 瞭解Python中常用的算術運算符,並瞭解運算符之間的先後運算順序 在各大常用的電腦語言中都有常見的算術運算符 ...
  • 這篇筆記依然是在做《Python語言程式設計》第5章迴圈的習題。其中有兩類問題需要記錄下來。 第一是如何畫圍棋棋盤。圍棋棋盤共有19縱19橫。其中,位於(0,0)的星位叫天元,其餘8個星位坐標分別是:(-6,6),(0,6),(6,6),(-6,0),(6,0),(-6,-6),(0,-6),(6, ...
  • 稍微關心編程語言的使用趨勢的人都知道,最近幾年,國內最火的兩種語言非 Python 與 Go 莫屬,於是,隔三差五就會有人問:這兩種語言誰更厲害/好找工作/高工資…… 對於編程語言的爭論,就是猿界的生理周期,每個月都要鬧上一回。到了年末,各類榜單也是特別抓人眼球,鬧得更凶。 其實,它們各有對方所無法 ...
  • 一、SSM搭建 1、使用的工具: myeclipse+jdk8+maven+MySQL+Tomcat8.5 2、配製文件截: 二、配置文件 1、web.xml 1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns:xsi="http:// ...
  • 轉載自CSDN的文章 https://blog.csdn.net/gongpulin/article/details/80972806 國內的go get問題的解決 轉載自CSDN的文章 https://blog.csdn.net/gongpulin/article/details/80972806 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...