Python進階:自定義物件實現切片功能
切片是 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 __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
Python貓
key 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__()
魔術方法,並用於實現自定義物件(以列表型別和字典型別為例)的切片功能,希望對你有所幫助。
參考閱讀:
官方文件getitem用法:http://t.cn/EbzoZyp
Python切片賦值原始碼分析:http://t.cn/EbzSaoZ
PS:本公眾號(Python貓)已開通讀者交流群,詳情請通過選單欄中的“交流群”來了解。
—————–
本文原創並首發於微信公眾號【Python貓】,後臺回覆“愛學習”,免費獲得20+本精選電子書。
相關文章
- Python 實現郵件傳送功能(進階)Python
- 自定義View事件之進階篇(四)-自定義Behavior實戰View事件
- 自定義View事件篇進階篇(二)-自定義NestedScrolling實戰View事件
- python-進階教程-對切片進行命名Python
- 新手進階|AutoCAD LT 2019 Mac自定義功能區的方法Mac
- vue-自定義指令-實現提示功能Vue
- video自定義實現視訊播放功能IDE
- Python進階:切片的誤區與高階用法Python
- Python進階:迭代器與迭代器切片Python
- 自定義物件池實踐物件
- 自定義檔案上傳功能實現方法
- python實現自定義執行緒池Python執行緒
- mysql使用自定義序列實現row_number功能MySql
- <4>Python切片功能剖析Python
- gRPC(七)進階:自定義身份驗證RPC
- 自定義限速功能實踐——Caffeine
- Python進階07 函式物件Python函式物件
- Python進階之物件導向Python物件
- SpringBoot自定義攔截器實現IP白名單功能Spring Boot
- Python實用技法第13篇:對自定義類物件排序:attrgetterPython物件排序
- 進階|教你使用自定義屬性功能管理 Word 文件中的待定內容
- 自定義限速功能實踐——Map 版本
- Python進階教程5——物件導向Python物件
- 簡單介紹Android自定義View實現時鐘功能AndroidView
- Android進階之自定義ViewGroup—帶你一步步輕鬆實現ViewPagerAndroidViewpager
- 自定義SpringMVC部分實現SpringMVC
- 自定義實現Complex類
- Android自定義拍照實現Android
- Net 實現自定義Aop
- EventSource的自定義實現
- 列印可自定義的字母金字塔(python實現)Python
- CoreText進階(七) 新增自定義View和對其View
- [iOS] [OC] NSNotificationCenter 進階及自定義(附原始碼)iOS原始碼
- Vuejs進階知識(二十四)【自定義Directive】VueJS
- 自定義註解+反射 實現給註解新增功能的效果反射
- python教程12-物件導向進階Python物件
- 聊聊自定義實現的SPI如何與spring進行整合Spring
- 自定義物件池在 Caffeine 框架中實踐物件框架