流畅的Python学习笔记
通过代码可以理解__len__()和__getitem__的功能。
在Python中,会使用特殊方法激活一些基本的对象操作,这些特殊方法用两个下划线开头。
比如len(obj)其实是调用了obj.__len__()
而obj[key]是调用了obj.__getitem__(key)
下面的例子来帮助理解这些特殊方法的用法。
import collections
Card = collections.namedtuple('扑克牌',['数字','花色'])
class FrenchDeck:
ranks = [str(n) for n in range(2,11)] + list('JQKA')
suits = '? ? ? ?'.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,pos):
return self._cards[pos]
def set_card(self,pos,card):
self._cards[pos] = card
def __setitem__(self,pos,card):
return self.set_card(pos,card)
collections.namedtuple()命名元组赋予每个位置一个含义,提供可读性和自文档性。它们可以用于任何普通元组,并添加了通过名字获取值的能力,通过索引值也是可以的。
我们知道元组访问方式一般是 元组名[0] 这样的。但是namedtuple赋予元组另一种通过名称获取值的能力。如下:
beer_card = Card('7','?')
print('beer_card[0] =',beer_card[0]) #一般元组访问方式
print('beer_card.数字 =',beer_card.数字) #用了namedtuple方法后可以使用key访问
输出为:
beer_card[0] = 7
beer_card.数字 = 7
获得一共有多少扑克,其实是调用了__len__()方法。
因此以下的2个代码是一样的。
deck = FrenchDeck()
print(len(deck))
print(deck.__len__())
输出为:
52
52
获得第一个元素和最后一个元素,和一般对序列的操作一样。
deck[0]
输出为:
扑克牌(数字='2', 花色='?')
deck[-1]
输出为:
扑克牌(数字='A', 花色='?')
随机抽取一张扑克牌,使用了 random的choice
每次都是随机抽取
from random import choice
choice(deck)
输出为:扑克牌(数字='5', 花色='?')
choice(deck)
输出为:扑克牌(数字='7', 花色='?')
查看最上面3张牌都是什么?
deck[:3]
输出为:
[扑克牌(数字='2', 花色='?'), 扑克牌(数字='3', 花色='?'), 扑克牌(数字='4', 花色='?')]
查看数字为A的全部牌,其实操作是先取得索引是12的牌,
2-10 9张 JQK 3张 A为第13张,因为索引从0开始因此是12。 之后每13张牌取1张。
deck[12::13]
输出为:
[扑克牌(数字='A', 花色='?'),
扑克牌(数字='A', 花色='?'),
扑克牌(数字='A', 花色='?'),
扑克牌(数字='A', 花色='?')]
因为__getitem__方法,所以deck对象可以迭代。因此我们使用for循环来顺序获得所有的牌。
for card in deck:
print(card)
一般 contains 方法可以实现成员检查的操作,如果没有的话 in 运算符按顺序做迭代搜索。
Card('4','?') in deck
输出为:
True
我们也可以进行洗牌操作,需要 random 的 shffle方法。
from random import shuffle
deck=FrenchDeck()
shuffle(deck)
deck[:5]