Python模型其实就是对Python框架的描述,它规范了这门语言自身构建模型的接口,这些模块包括但不限于序列、迭代器、函数、类和上下文管理器
Python解释器碰到特殊的语法时,会使用特殊方法去激活一些基本的对象操作,这些特殊方法的名字以两个下划线开题,以两个下划线结尾(例如__getitem__)
比如obj[key]的背后就是__getitem__方法,为了求得my_collection[key]的值,解释器实际上会调用my_collection.__getitem__(key)方法。 len(obj)的背后就是__len__方法,为了求得my_collection的长度,解释器实际上会调用my_collection.__len__()方法。
这些特殊方法名能让对象的实现和支持以下的语法构架,并与之交互:
- 迭代
- 集合类
- 属性访问
- 运算符重载
- 函数和方法调用
- 对象的创建和销毁
- 字符串表示形式和格式化
- 管理上下文(即with块)
一摞Python风格的纸牌
示例: 展示如何实现__getitem__和__len__这两个特殊方法
import collections Card = collections.namedtuple('Card', ['rank', 'suit']) class FrenchDeck(object): # 牌面 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, item): return self._cards[item]
说明: 使用collections.nametuple构建一个简单的类来表示一张纸牌,collections.nametuple()方法可以构建只有少数属性但没有方法的对象。
# Card类的使用
beer_card = Card('7', 'diamonds') print(beer_card)
使用len()方法查看一叠牌有多少张
deck = FrenchDeck() print(len(deck))
从一叠牌中抽取特定的一张牌, 比如说第一张和最后一张
# 抽取第一张牌
print(deck[0]) # 抽取最后一张牌
print(deck[-1])
因为__getitem__方法把[]操作交给了self._cards列表,所以deck类自动支持切片操作。
print(deck[0:3])
因为类实现了__getitem__方法,所以这一叠牌变成了可迭代对象,
# 正向迭代 for card in deck: print(card) # 反向迭代 for card in reversed(deck): print(card)
如果一个类没有实现__contains__方法,那么in运算符就会按顺序做一次迭代搜索,所以,in运算符可以用在FrenchDeck类上。
print(Card('Q', 'hearts') in deck) # True print(Card('7', 'bearts') in deck) # False
对纸牌类对象进行排序
suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0) print(suit_values) # {'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)
说明: 排序主要是使用sorted内置方法,参数key接收排序的函数,suit_values表示花色的权重,排序的方法spades_high接收一张纸牌,然后通过获取纸牌的牌面和花色返回牌面的权值,
权值的计算公式为: 牌面 * 4 + 花色对应的value