這一章中作者簡要的介紹了python數據模型,主要是python的一些特殊方法。比如__len__, __getitem__. 並用一個紙牌的程式來講解了這些方法 首先介紹下Tuple和nametuple的區別: Nametuple是類似於元組的數據類型。除了能夠用索引來訪問數據,還支持用方便的屬性 ...
這一章中作者簡要的介紹了python數據模型,主要是python的一些特殊方法。比如__len__, __getitem__. 並用一個紙牌的程式來講解了這些方法
首先介紹下Tuple和nametuple的區別:
Nametuple是類似於元組的數據類型。除了能夠用索引來訪問數據,還支持用方便的屬性名來訪問數據。
傳統的元組訪問如下。對每個元素的訪問都必須通過索引來找到。這種找法很不直觀
tup1=('abc','def','ghi')
print tup1[1]
使用nametuple來構造:
tup2=namedtuple('tuple2',['name','age','height'])
t1=tup2('zhf','33','175')
print t1
print t1.age
print t1.height
print t1.name
得到結果如下,namedtupel中tuple2是類型名,name,age,height是屬性名字
從上面的訪問可以看到,直接用t1.age的方法訪問更加直觀。當然也可以用索引比如t1[0]的方法來訪問
namedtupe1也支持迭代訪問:
for t in t1:
print 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
下麵來看下書中的紙牌例子,代碼如下:
from collections import namedtuple
Card=namedtuple('Card',['rank','suit'])
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]
if __name__=='__main__':
deck=FrenchDeck()
print len(deck)
print 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__方法,還可以進行迭代訪問,如下:
for d in deck:
print 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__
代碼如下:
class vector:
def __init__(self,x=0,y=0):
self.x=x
self.y=y
def __repr__(self):
return 'Vector(%r,%r)' % (self.x,self.y)
def __abs__(self):
return hypot(self.x,self.y)
def __bool__(self):
return bool(abs(self))
def __add__(self,other):
x=self.x+other.x
y=self.y+other.y
return vector(x,y)
def __mul__(self, scalar):
return vector(self.x*scalar,self.y*scalar)
if __name__=='__main__':
v1=vector(1,2)
v2=vector(2,3)
print v1+v2
print abs(v1)
print v1*3
運算結果如下:
在這裡__add__,__mul__,__abs__分別實現了向量加法,乘法,以及求模的運算。
值得一提的是__repr__的方法。這個方法是在需要列印對象的時候調用。例如print vector(1,2)的時候得到vector(1,2). 否則就是表示對象的字元串:<Vector object at 0x0000>.這個__repr__和__str__的作用是類似的