自Python 2.6开始,namedtuple就加入到Python里,用以构建只有少数属性但是没有方法的对象

用namedtuple实现扑克牌类和记录城市信息的示例。

示例1,实现扑克牌类:

# -*- coding: utf-8 -*-

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):
        ''' 定义len() '''
        return len(self._cards)

    def __getitem__(self, position):
        ''' 定义下标index访问 '''
        return self._cards[position]



deck = FrenchDeck()

from random import choice
print(choice(deck))

# __len__
print(len(deck))

# __getitem__
print(deck[:3])
print(deck[12::13])

# 反向迭代 reversed 返回是迭代对象 注意同一个迭代对象只能遍历一次
# print(reversed(deck))
for card in reversed(deck):
    print(card)

# 迭代通常是隐式的,譬如说一个集合类型没有实现 __contains__ 方法,
# 那么in运算符就会按顺序做一次迭代搜索。于是,in运算符可以用在我们的
# FrenchDeck 类上,因为它是可迭代的:
print(Card('Q', 'hearts') in deck)
print(Card('Q', 'beasts') in deck)

suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)

def spades_high(card):
    ''' 排序函数算法:52张牌 0-51 数值对应的下标x4+花色权值'''
    rank_value = FrenchDeck.ranks.index(card.rank)
    # print(rank_value, len(suit_values), suit_values[card.suit])
    return rank_value * len(suit_values) + suit_values[card.suit]


card = choice(deck)
print(card)
print(spades_high(card))

for card in sorted(deck, key=spades_high):
    print(card)
    

示例1说明:

一张扑克牌由数值和花色两种属性组成,因此用元组和具名元组存储是再适合不过了,具名元组是最合适的实现。

Card = collections.namedtuple(‘Card’, [‘rank’, ‘suit’]) 也可以写成 Card = collections.namedtuple(‘Card’, ‘rank suit’)

另外还实现了获取长度、下标访问、排序等方法,简洁又强大。

示例2,记录城市信息:

>>> from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates')
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667)) # 元素是元组也可以
>>> tokyo 
City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
>>> tokyo.coordinates
(35.689722, 139.691667) 
>>> tokyo[1]
'JP'
>>> City._fields
('name', 'country', 'population', 'coordinates')
>>> LatLong = namedtuple('LatLong', 'lat long') 
>>> delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889)) # namedtuple嵌套
>>> delhi = City._make(delhi_data)
>>> delhi._asdict()
OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935), ('coordinates', LatLong(lat=28.613889, long=77.208889))])
>>> for key, value in delhi._asdict().items():
...     print(key + ':', value)

示例2说明:

创建一个具名元组需要两个参数,一个是类名,另一个是类的各个字段的名字。后者可以是由数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串。 存放在对应字段里的数据要以一串参数的形式传入到构造函数中(注意,元组的构造函数却只接受单一的可迭代对象)。 你可以通过字段名或者位置来获取一个字段的信息。 _fields 属性是一个包含这个类所有字段名称的元组。 用 _make() 通过接受一个可迭代对象来生成这个类的一个实例,它的作用跟 City(*delhi_data) 是一样的。 _asdict() 把具名元组以 collections.OrderedDict 的形式返回,我们可以利用它来把元组里的信息友好地呈现出来。

整理自《流畅的Python》关于namedtuple的内容。