Python数据模型
Python风格的设计思想,体现在python的数据模型上,数据模型其实是对python框架的描述,它规范了这门语言自身构建模块的接口,这些模块包括但不限于序列、迭代器、函数、类和上下文管理器。
1.1 一摞Python风格的纸牌
import collections # collections.namedtuple用以构建只有少数属性但没有方法的对象
from random import choice
Card = collections.namedtuple('Card', ['rank', 'suit']) # 构建纸牌对象,分别有序列和花色两个属性
class FrenchDeck:
ranks = [str(n) for n in range(2, 11)] + list('JQKA') # 分别构建2-10和JQKA序列,用+进行链接
suits = 'spades diamonds clubs hearts'.split() # 构建花色的list
def __init__(self): # 创建一副牌,按照花色顺序建立2-A
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
def __len__(self): # len作为特殊函数,可以len(对象)使用,所以只有self;
return len(self._cards) # self._cards是list,可以直接使用len来读取长度
def __getitem__(self, position): # 返回postion索引对应数值
return self._cards[position]
deck = FrenchDeck()
# __getitem__将[]的操作提交给self._cards列表,所以支持以下操作:随机抽取、索引、切片、迭代
choice(deck)
deck[:3] # 提取前三张牌
deck[12::13] # 从deck[12]开始,每13张牌取一张,即提取所有的A牌
for card in reversed(deck): #doctest: +ELLIPSIS 此命令可用来避免省略号
print(card)
Card('Q', 'hearts') in deck
# 给扑克牌排序,因为FrenchDeck中实现了__len__和__getitem__两个方法,所以如同python自有的数据类型
# 自然,可以使用标准库中的random.choice reversed sorted函数
suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
def spades_high(card):
rank_value = FrenchDeck.ranks.index(card.rank)
return rank_value*len(suit_values) + suit_values[card.suit]
for card in sorted(deck, key=spades_high):
print(card)
1.2 如何使用特殊方法
特殊方法的存在是为了被Python解释器调用,例如len(Deck),而不是Deck.__len__();
特殊方法的调用是隐式的;
不要随意添加特殊方法。
1.2.1模拟数值类型
from math import hypot
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))
return bool(self.x or self.y)
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)
1.2.2 字符串表示形式
st = "weihua"
print("%r" % st)
print("{!r}".format(st))
__repr__
与__str__
的区别在于:
__repr__
的实现中,用到了%r来获取对象各个属性的标准字符串表示形式,在交互式控制台打印一个对象;使用Vector(3,4);后者在str()函数被使用,或者在print函数打印一个对象的时候才被调用,并且它返回的字符串对终端用户更友好。
1.2.3 算术运算符
通过定义方法:__add__
和__mul__
,实现类中+和*两个算术运算符
1.2.4 自定义的布尔值
bool(x)的背后是调用x.__bool__()的结果