国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python中序列的修改、散列與切片詳解

2020-01-04 16:49:36
字體:
來源:轉載
供稿:網友

前言

本文主要給大家介紹了關于Python中序列的修改、散列與切片的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。

Vector類:用戶定義的序列類型

  我們將使用組合模式實現 Vector 類,而不使用繼承。向量的分量存儲在浮點數數組中,而且還將實現不可變扁平序列所需的方法。

Vector 類的第 1 版要盡量與前一章定義的 Vector2d 類兼容。

Vector類第1版:與Vector2d類兼容

Vector 類的第 1 版要盡量與前一章定義的 Vector2d 類兼容。然而我們會故意不讓 Vector 的構造方法與 Vector2d 的構造方法兼容。為了編寫 Vector(3, 4) 和 Vector(3, 4, 5) 這樣的代碼,我們可以讓 __init__ 方法接受任意個參數(通過 *args);但是,序列類型的構造方法最好接受可迭代的對象為參數,因為所有內置的序列類型都是這樣做的。

測試 Vector.__init__ 和 Vector.__repr__ 方法

>>> Vector([3.1, 4.2])Vector([3.1, 4.2])>>> Vector((3, 4, 5))Vector([3.0, 4.0, 5.0])>>> Vector(range(10))Vector([0.0, 1.0, 2.0, 3.0, 4.0, ...])

vector_v1.py:從 vector2d_v1.py 衍生而來

from array import arrayimport reprlibimport mathclass Vector: typecode = 'd' def __init__(self, components): self._components = array(self.typecode, components)  #self._components是“受保護的”實例屬性,把Vector的分量保存在一個數組中 def __iter__(self): return iter(self._components)    #為了迭代,我們使用self._components構建一個迭代器 def __repr__(self): components = reprlib.repr(self._components)   #使用reprlib.repr()函數獲取self._components 的有限長度表示形式(如 array('d', [0.0, 1.0, 2.0, 3.0, 4.0, ...])) components = components[components.find('['):-1]  #把字符串插入 Vector 的構造方法調用之前,去掉前面的array('d' 和后面的 ) return 'Vecotr({})'.format(components)   #直接使用 self._components 構建 bytes 對象 def __str__(self): return str(tuple(self)) def __bytes__(self): return (bytes([ord(self.typecode)]) +  bytes(self._components)) def __eq__(self, other): return tuple(self) == tuple(other) def __abs__(self): return math.hypot(sum(x * x for x in self))   #不能使用hypot方法了,因此我們先計算各分量的平方之和,然后再使用sqrt方法開平方 def __bool__(self): return bool(abs(self)) @classmethod def frombytes(cls, octets): typedcode = chr(octets[0]) memv = memoryview(octets[1:]).cast(typedcode) return cls(memv)      #我們只需在 Vector2d.frombytes 方法的基礎上改動最后一行:直接把memoryview傳給構造方法,不用像前面那樣使用*拆包

協議和鴨子類型

在 Python 中創建功能完善的序列類型無需使用繼承,只需實現符合序列協議的方法。不過,這里說的協議是什么呢?

在面向對象編程中,協議是非正式的接口,只在文檔中定義,在代碼中不定義。例如,Python 的序列協議只需要 __len__ 和 __getitem__ 兩個方法。任何類(如 Spam),只要使用標準的簽名和語義實現了這兩個方法,就能用在任何期待序列的地方。Spam 是不是哪個類的子類無關緊要,只要提供了所需的方法即可。

class FrenchDeck: ranks = [str(n) for n in range(2, 11)] + list('JQKA') suits = 'spades diamonds clubs hearts'.split() def __init__(self): self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks] def __len__(self): return len(self._cards) def __getitem__(self, position): return self._cards[position]

協議是非正式的,沒有強制力,因此如果你知道類的具體使用場景,通常只需要實現一個協議的部分。例如,為了支持迭代,只需實現__getitem__ 方法,沒必要提供 __len__ 方法。

Vector類第2版:可切片的序列

如 FrenchDeck 類所示,如果能委托給對象中的序列屬性(如self._components 數組),支持序列協議特別簡單。下述只有一行代碼的 __len__ 和 __getitem__ 方法是個好的開始:

class Vector: # 省略了很多行 # ... def __len__(self): return len(self._components) def __getitem__(self, index): return self._components[index]

添加這兩個方法之后,就能執行下述操作了:

>>> v1 = Vector([3, 4, 5])>>> len(v1)>>> v1[0], v1[-1](3.0, 5.0)>>> v7 = Vector(range(7))>>> v7[1:4]array('d', [1.0, 2.0, 3.0])

可以看到,現在連切片都支持了,不過尚不完美。如果 Vector 實例的切片也是 Vector 實例,而不是數組,那就更好了。前面那個FrenchDeck 類也有類似的問題:切片得到的是列表。對 Vector 來說,如果切片生成普通的數組,將會缺失大量功能。

為了把 Vector 實例的切片也變成 Vector 實例,我們不能簡單地委托給數組切片。我們要分析傳給 __getitem__ 方法的參數,做適當的處理。

切片原理

了解 __getitem__ 和切片的行為

>>> class MySeq:... def __getitem__(self, index):...  return index... >>> s = MySeq()              >>> s[1]                      #__getitem__直接返回傳給它的值>>> s[1:4]                     #[1:4]表示變成了slice(1, 4, None)slice(1, 4, None)>>> s[1:4:2]                    #[1:4:2]的意思為從第1個索引開始,到第4個索引結束,步長為2slice(1, 4, 2)          >>> s[1:4:2, 9]                  (slice(1, 4, 2), 9)                #神奇的事情發生了..wtf...如果[]中有逗號,那么__getitem__接收的是元祖>>> s[1:4:2, 7:9]                 #元祖中還可以包含多個切片對象(slice(1, 4, 2), slice(7, 9, None))

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 内丘县| 大安市| 天峻县| 海城市| 嘉黎县| 通化市| 锦屏县| 晋州市| 紫金县| 黎平县| 临朐县| 天等县| 商河县| 紫云| 遵义市| 嘉鱼县| 塔河县| 白城市| 通海县| 永丰县| 达孜县| 南开区| 新化县| 页游| 辽宁省| 灵台县| 安达市| 淮南市| 八宿县| 张家口市| 日土县| 湖口县| 嘉定区| 阿荣旗| 门头沟区| 延安市| 电白县| 屏边| 磐石市| 衡东县| 广平县|