用一个例子理解collections.namedtuple的用法

# 定义了一个namedtuple类型,包含name, sex和age属性
User = collections.namedtuple('User', ['name', 'sex', 'age'])
# 实例化
user = User(name='zhangly', sex='male', age=24)
# 打印它查看
print user
>>> User(name='zhangly', sex='male', age=24)
# 打印user的三个属性
print user.name, user.sex, user.age
>>> zhangly male 24
# 也可以修改对象的属性
user = user._replace(age=99)
print user
>>> User(name='zhangly', sex='male', age=99)
# 将user对象转换为字典
user_dict = user._asdict()
print user_dict
>>> OrderedDict([('name', 'zhangly'), ('sex', 'male'), ('age', 99)])

namedtuple是继承自tuple的子类。namedtuple创建一个和tuple类似的对象,而且对象拥有可访问的属性。
看完上面的例子后,就比较容易理解接下来的例子了。

一摞python风格的纸牌

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]
    def __len__(self):
        return len(self._cards)
    def __getitem__(self, position):
        return self._cards[position]

让我们实例化它

deck = FrenchDeck()

使用len()查看一叠牌有多少张

len(deck)
>>> 52

这里能够用len()函数去查看牌的数量,是因为我们在FrenchDeck类里声明了__len__方法。而__getitem__方法,则可以让我们像列表一样访问对象。

deck[0]
>>> Card(rank='2', suit='spades')
deck[-1]
>>> Card(rank='A', suit='hearts')

当然我们也可以使用random函数来随机抽取一张牌

from random import choise
choice(deck)
>>> Card(rank='Q', suit='diamonds')
choice(deck)
>>> Card(rank='4', suit='diamonds')
choice(deck)
>>> Card(rank='4', suit='hearts')

使用了__getitem__魔法方法,我们就可以像列表一样去操作self._cards,当别人调用你的代码后,不再考虑怎么得到元素的总和,可以更方便的使用标准库的方法。
我们也可以根据扑克牌的大小对它进行排序,同时还要加上对花色的判定。
黑桃最大,红桃次之,方块再次,梅花最小。

# 给定花色的大小
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]
# 使用sorted函数进行排序
for card in sorted(deck, key=spades_high):
    print card

sorted()中key的参数是一个函数,在排序前它会将列表内的每个值传入这个函数,其返回的值用作排序依据。下面是个简单的例子。

example_list = [9, 2, 5, 8, 1, 3, 7, 6, 0, 4]
sorted(example_list, key=lambda X: X*-1)
>>> [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

From zero to hero