import collections
Card = collections.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]
print(self._cards)
def __len__(self):
return len(self._cards)
def __getitem__(self, item):
return self._cards[item]
deck = FrenchDeck()
print(len(deck))
print(deck[0])
上述代码实现了一个自定义的纸牌类,初始化生成一个52张纸牌的tuple,那么直接对这个类使用Python自带的对列表操作的方法是不行的,比如len
可以利用魔术方法__len__,定义对纸牌类进行len操作时,即返回len(self.cards),定义__getitem__同理,实现了这两个方法后,就可以对实例化的纸牌类对象使用len和deck[0]这样的方法了,甚至可以实现切片操作,可以理解为切片操作也是基于基本的__getitem__来实现的,所以一旦你为自定义的类实现了这个魔术方法,你可以对他进行切片、迭代、反向迭代、in运算符(一个集合类型没有实现__contains__方法,那么in就会按顺序做一次迭代搜索)、排序。
也就是说通过实现__len__和__getitem__这两个特殊方法,FrenchDeck就跟一个python自有的序列数据类型一样,可以体现出python的核心语言特性
特殊方法是被python解释器调用的,自己并不需要去调用,也就是说没有my_object.__len__()这种写法,应该使用len(my_object),python会自己去调用其中你实现的__len__方法
很多时候特殊方法的调用是隐式的,比如for i in x:,背后其实用的是iter(x),这个函数背后则是x.__iter__()方法