Python進階:自定義對象實現切片功能

来源:https://www.cnblogs.com/pythonista/archive/2018/12/30/10199342.html
-Advertisement-
Play Games

2018-12-31 更新聲明:切片系列文章本是分三篇寫成,現已合併成一篇。合併後,修正了一些嚴重的錯誤(如自定義序列切片的部分),還對行文結構與章節銜接做了大量改動。原系列的單篇就不刪除了,畢竟也是有單獨成篇的作用。特此聲明,請閱讀改進版—— Python進階:全面解讀高級特性之切片!https: ...


 

2018-12-31 更新聲明:切片系列文章本是分三篇寫成,現已合併成一篇。合併後,修正了一些嚴重的錯誤(如自定義序列切片的部分),還對行文結構與章節銜接做了大量改動。原系列的單篇就不刪除了,畢竟也是有單獨成篇的作用。特此聲明,請閱讀改進版—— Python進階:全面解讀高級特性之切片!https://mp.weixin.qq.com/s/IRAjR-KHZBPEEkdiofseGQ

 

 

切片是 Python 中最迷人最強大最 Amazing 的語言特性(幾乎沒有之一),在《Python進階:切片的誤區與高級用法》中,我介紹了切片的基礎用法、高級用法以及一些使用誤區。這些內容都是基於原生的序列類型(如字元串、列表、元組......),那麼,我們是否可以定義自己的序列類型並讓它支持切片語法呢?更進一步,我們是否可以自定義其它對象(如字典)並讓它支持切片呢?

1、魔術方法:__getitem__()

想要使自定義對象支持切片語法並不難,只需要在定義類的時候給它實現魔術方法 __getitem__() 即可。所以,這裡就先介紹一下這個方法。

語法: object.__getitem__(self, key)

官方文檔釋義:Called to implement evaluation of self[key]. For sequence types, the accepted keys should be integers and slice objects. Note that the special interpretation of negative indexes (if the class wishes to emulate a sequence type) is up to the __getitem__() method. If key is of an inappropriate type, TypeError may be raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values), IndexError should be raised. For mapping types, if key is missing (not in the container), KeyError should be raised.

概括翻譯一下:__getitem__() 方法用於返回參數 key 所對應的值,這個 key 可以是整型數值和切片對象,並且支持負數索引;如果 key 不是以上兩種類型,就會拋 TypeError;如果索引越界,會拋 IndexError ;如果定義的是映射類型,當 key 參數不是其對象的鍵值時,則會拋 KeyError 。

2、自定義序列實現切片功能

接下來,我們定義一個簡單的 MyList ,並給它加上切片功能。(PS:僅作演示,不保證其它功能的完備性)。

  class MyList():
      def __init__(self):
          self.data = []
      def append(self, item):
          self.data.append(item)
      def __iter__(self):
          return self
      def __getitem__(self, key):
          print("key is : " + str(key))
          return self.data[key]
  ​
  l = MyList()
  l.append("My")
  l.append("name")
  l.append("is")
  l.append("Python貓")
  ​
  print(l[3])
  print(l[:2])
  print(l['hi'])
  ​
  ### 輸出結果:
  key is : 3
  Pythonkey is : slice(None, 2, None)
  ['My', 'name']
  key is : hi
  Traceback (most recent call last):
  ...
  TypeError: list indices must be integers or slices, not str

從輸出結果來看,自定義的 MyList 既支持按索引查找,也支持切片操作,這正是我們的目的。

特別需要說明的是,此例中的 __getitem__() 方法會根據不同的參數類型而實現不同的功能(取索引位值或切片值),也會妥當地處理異常,所以並不需要我們再去寫繁瑣的處理邏輯。網上有不少學習資料完全是在誤人子弟,它們會教你區分參數的不同類型,然後寫一大段代碼來實現索引查找和切片語法,簡直是畫蛇添足。下麵的就是一個代表性的錯誤示例:

  
  ###略去其它代碼####
  def __getitem__(self, index):
      cls = type(self)
      if isinstance(index, slice):  # 如果index是個切片類型,則構造新實例
         return cls(self._components[index])
      elif isinstance(index, numbers.Integral):  # 如果index是個數,則直接返回
          return self._components[index]
      else:
          msg = "{cls.__name__} indices must be integers"
          raise TypeError(msg.format(cls=cls))

3、自定義字典實現切片功能

切片是序列類型的特性,所以在上例中,我們不需要寫切片的具體實現邏輯。但是,對於其它非序列類型的自定義對象,就得自己實現切片邏輯。以自定義字典為例(PS:僅作演示,不保證其它功能的完備性):

  
  class MyDict():
      def __init__(self):
          self.data = {}
      def __len__(self):
          return len(self.data)
      def append(self, item):
          self.data[len(self)] = item
      def __getitem__(self, key):
          if isinstance(key, int):
              return self.data[key]
          if isinstance(key, slice):
              slicedkeys = list(self.data.keys())[key]
              return {k: self.data[k] for k in slicedkeys}
          else:
              raise TypeError
  ​
  d = MyDict()
  d.append("My")
  d.append("name")
  d.append("is")
  d.append("Python貓")
  print(d[2])
  print(d[:2])
  print(d[-4:-2])
  print(d['hi'])
  ​
  ### 輸出結果:
  is
  {0: 'My', 1: 'name'}
  {0: 'My', 1: 'name'}
  Traceback (most recent call last):
  ...
  TypeError

上例的關鍵點在於將字典的鍵值取出,並對鍵值的列表做切片處理,其妙處在於,不用擔心索引越界和負數索引,將字典切片轉換成了字典鍵值的切片,最終實現目的。

4、小結

最後小結一下:本文介紹了__getitem__() 魔術方法,並用於實現自定義對象(以列表類型和字典類型為例)的切片功能,希望對你有所幫助。

 

參考閱讀:

Python進階:切片的誤區與高級用法

官方文檔getitem用法:http://t.cn/EbzoZyp

Python切片賦值源碼分析:http://t.cn/EbzSaoZ

 

PS:本公眾號(Python貓)已開通讀者交流群,詳情請通過菜單欄中的“交流群”來瞭解。

 

-----------------

本文原創並首發於微信公眾號【Python貓】,後臺回覆“愛學習”,免費獲得20+本精選電子書。


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

-Advertisement-
Play Games
更多相關文章
  • 開篇來自於經典的“保全的哲學三問”(你是誰,在哪兒,要幹嘛) 問題一、ElasticSearch是什麼?有什麼用處? 答:截至2018年12月28日,從ElasticSearch官網(https://www.elastic.co/cn/products)上,得知:ElasticSearch是基於 J ...
  • url配置就像Django所支撐網站的目錄。它的本質是url與要被該url調用的視圖函數之間的映射表;通過這個映射表可以告知Django,對於客戶端發來的某個url該執行那些代碼。 一、簡單的路由配置 二、有名分組 上面我們說了,帶()就是進行了分組,就會作為位置參數傳給視圖函數,視圖函數也要以位置 ...
  • 一 集合 2018-12-30 集合是一個無序不重覆元素的集。基本功能包括關係測試和消除重覆元素。 創建集合:大括弧或 set() 函數可以用來創建集合。註意:想要創建空集合,你必須使用 set() 而不是 {},後者用於創建空字典。大括弧也不可以創建元素含有字典與列表的集合。 二 、 文件操作 1 ...
  • Spring的類型轉換 以前在面試中就有被問到關於spring數據綁定方面的問題,當時對它一直只是朦朦朧朧的概念,最近稍微閑下來有時間看了一下其中數據轉換相關的內容,把相應的內容做個記錄。 下麵先說明如何去用,然後再放一下個人看參數綁定源碼的一些筆記,可能由於實力不夠,有些地方說的不是很正確,如果有 ...
  • 本地運行: ...
  • 前言: 用Python寫安卓APP肯定不是最好的選擇,但是肯定是一個很偷懶的選擇 我們使用kivy開發安卓APP,Kivy是一套專門用於跨平臺快速應用開發的開源框架,使用Python和Cython編寫,對於多點觸控有著非常良好的支持,不僅能讓開發者快速完成簡潔的交互原型設計,還支持代碼重用和部署,絕 ...
  • 一、python assert的作用: 根據Python 官方文檔解釋(https://docs.python.org/3/reference/simple_stmts.html#assert), "Assert statements are a convenient way to insert d ...
  • Swagger2 方式,一定會讓你有不一樣的開發體驗:功能豐富 :支持多種註解,自動生成介面文檔界面,支持在界面測試API介面功能;及時更新 :開發過程中花一點寫註釋的時間,就可以及時的更新API文檔,省心省力;整合簡單 :通過添加pom依賴和簡單配置,內嵌於應用中就可同時發佈API介面文檔界面,不... ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...