這一章中作者簡要的介紹了python資料模型,主要是python的一些特殊方法。比如__len__, __getitem__. 並用一個紙牌的程式來講解了這些方法
首先介紹下Tuple和nametuple的區別:
Nametuple是類似於元組的資料類型。除了能夠用索引來訪問資料,還支援用方便的屬性名稱來訪問資料。
傳統的元組訪問如下。對每個元素的訪問都必須通過索引來找到。這種找法很不直觀
tup1=(,,)tup1[1]
使用nametuple來構造:
tup2=namedtuple(,[,,])t1=tup2(,,)t1t1.aget1.heightt1.name
得到結果如下,namedtupel中tuple2是類型名,name,age,height是屬性名稱字
從上面的訪問可以看到,直接用t1.age的方法訪問更加直觀。當然也可以用索引比如t1[0]的方法來訪問
namedtupe1也支援迭代訪問:
t t1: t
和元組一樣,namedtupel中的元素也是不可變更的。如果執行t1.age+=1。將會提示無法設定元素
Traceback (most recent call last):
File "E:/py_prj/fluent_py.py", line 17, in <module>
t1.age+=1
AttributeError: can't set attribute
下面來看下書中的紙牌例子,代碼如下:
collections namedtupleCard=namedtuple(,[,])FrenchDeck: ranks=[str(n) n range(2,11)] + list() suits=.split() __init__(self): self._cards=[Card(rank,suit) suit self.suits
rank self.ranks] __len__(self): len(self._cards) __getitem__(self, position): self._cards[position]__name__==: deck=FrenchDeck() len(deck) deck[1]
首先定義了的紙牌元組Card, rank代表紙牌數字,suit代表紙牌花色。然後在FrenchDeck首先定義了ranks和suit的具體指。在__init__中對self._cards進行初始化。
__len__反饋self._cards的長度。__getitem__反饋具體的紙牌值。
結果如下,紙牌的長度為52,其中deck[1]為Card(rank=’3’,suit=’spades’)
可以看到len(deck)其實調用的是__len__方法。deck[1]調用的是__getitem__
由於有了__getitem__方法,還可以進行迭代訪問,如下:
d deck: d
既然是可迭代的,那麼我們可以類比隨機發牌的機制。
from random import choice
print choice(deck)
得到結果:
Card(rank='9', suit='hearts')
接下來看另外一個例子,關於向量運算的。比如有向量1 vector1(1,2),向量2 vector2(3,4)。那麼vector1+vector2的結果應該是(4,6)。Vector1和vector2都是向量,如何?運算呢。方法是__add__,__mul__
代碼如下:
vector: __init__(self,x=0,y=0): self.x=x self.y=y __repr__(self): % (self.x,self.y) __abs__(self): hypot(self.x,self.y) __bool__(self): bool(abs(self)) __add__(self,other): x=self.x+other.x y=self.y+other.y vector(x,y) __mul__(self, scalar): vector(self.x*scalar,self.y*scalar)
__name__==: v1=vector(1,2) v2=vector(2,3) v1+v2 abs(v1) v1*3
運算結果如下:
在這裡__add__,__mul__,__abs__分別實現了向量加法,乘法,以及求模的運算。
值得一提的是__repr__的方法。這個方法是在需要列印對象的時候調用。例如print vector(1,2)的時候得到vector(1,2). 否則就是表示對象的字串:<Vector object at 0x0000>.這個__repr__和__str__的作用是類似的