import collections
import random

Card = collections.namedtuple('Card', ["color","num"])

class Deck(object):
    nums = [str(i) for i in range(2,11)] + list("AJQK")
    colors = ["heart", "spade", "diamond", "club"]

    def __init__(self):
        self._cards = [Card(color,num) for color in Deck.colors for num in Deck.nums]

    def __getitem__(self, index):
        return self._cards[index]

    def __len__(self):
        return len(self._cards)



d = Deck()
print(d[0])
print(d[1])
print(d[51])
print(len(d))

for i in d:
    print(i)
print(d[1:5])

print(random.choice(d))
print(Card('heart','Q') in d)

def setitem(deck, index, card):
    deck._cards[index] = card

Deck.__setitem__ = setitem
random.shuffle(d)
  1. 在需要创建大量简单类(如Card,只有两个属性需要访问)的实例的时候,使用namedtuple十分直观,简洁。

  2. __len__方法为使用len()函数提供了依据。CPython中是如何实现len()函数的呢?
    实际上,在源码中,cpython的一切对象都源自于PyVarObject ,这其中有个变量ob_size。使用len()可以直接将它返回,更快。

  3. __getitem__方法的神奇之处在于:实现了这一方法后,实例对象可以用for迭代,可以用index访问,可以切片,还可以使用in判断是否存在,更甚者可以使用random.choice(),当然也可使用sorted或reversed.
    这是由于实现了__getitem__后python解释器,可以从index=0开始迭代,这就实现了iter的功能,同时,也可以从index=0开始扫描进而实现了in的功能。

  4. 但是没有__setitem__方法,实例不能完成random.shuffle().
    可以在类中进行补充,也可以动态绑定。
def setitem(deck, index, card):
    deck._cards[index] = card # 不能是deck[index]会形成无穷递归

 >>>Deck.__setitem__ = setitem # 类方法的绑定