参考资料Luciano Ramalho《流畅的python》
1、具名元组
from collections import namedtuple
City = namedtuple('City', 'name,country,population,coordinates')
# 创建一个具名元组需要两个参数,一个是类名,另一个是类的各个字段的名字。
# name country population coordinates都被称为“字段名”
# 后者也可以是由数个字符串组成的可迭代对象
# ['name','country','population','coordinates']
# 或者是由空格或逗号分隔开的字段名组成的字符串
# 'name,country,population,coordinates'
# 'name country population coordinates'
tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
# 存放在对应字段里的数据要以一串参数的形式传入到构造函数中(注意,元组的构造函数却只接受单一的可迭代对象)
# 这个“却”字是相对于上面具名元组的创建而言的,因为在上面,参数各个字段名的传入就可以用多种对象
print(tokyo)
# City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
print(tokyo.population)
# 36.933
print(tokyo[1])
# JP
# 可以通过“字段名”或者“位置(index)”来获取一个字段的信息。
2、一摞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()
# [str(n) for n in range(2, 11)] + list('JQKA') 即为['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
# list('JQKA') 即为['J', 'Q', 'K', 'A']
# 'spades diamonds clubs hearts'.split()即为['spades', 'diamonds', 'clubs', 'hearts']
def __init__(self):
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
# 类FrenchDeck的实例已被创建就会拥有属性_cards,该属性是一个list,list中的元素都是有名元组,这些元组都是由生成器
# collections.namedtuple('Card', 'rank,suit')生成的。在向这个生成器传入参数时,运用了遍历操作。
def __len__(self):
return len(self._cards)
# 定义了一个实例方法,返回值是这个类的属性_cards的长度
# 在计算机执行指令len(object)时,会立即映射这个方法,返回该方法的返回值,
# 此时,len指令没有什么关于len本身的特定意义,只是简单地映射了这个方法。
def __getitem__(self, position):
return self._cards[position]
# 在定义了方法__getitem__以后,这个对象就变得iterable,可以当做可迭代对象来使用
# 具体把它当做什么可迭代对象,就要由__getitem__的返回值来定了
# 一般而言,这个可迭代对象存储在实例的一个属性里
deck = FrenchDeck()
# 我们创建了一个对象deck
# 它具有属性_cards,它可具有方法__len__和__getitem__
# print(len(deck))
# print(deck[0]) # 第一张纸牌,应该是黑桃2
# print(deck[-1]) # 最后一张纸牌,应该是红桃A
# 上两行的代码得以实现是因为方法__getitem__
# from random import choice
#
# print(choice(deck)) # 从一个iterable中随机选取一个
# print(choice(deck))
# print(choice(deck))
# print(choice(deck))
# for card in deck:
# print(card)# 这里用到了方法__getitem__
# # 还可以反向迭代
# for card in reversed(deck):
# print(card)
suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0) # suit的值
def spade_high(card):
rank_value = FrenchDeck.ranks.index(card.rank) # rank的值
# 在实例deck里面,每一个元素都是一个有名tuple,我们获取这个tuple的属性rank,即得到了扑克牌的点数,
# 然后用index函数得到了点数在列表FrenchDeck.ranks中对应的索引,并将它作为扑克牌排序的依据之一赋值给rank_value
return rank_value * len(suit_values) + suit_values[card.suit]
# 这个排序依据的含义:
# suit_values[card.suit]就是花色在字典suit_values中对应的值
# len(suit_values)就是4
# rank_value*4,也就是扑克牌的数字乘以4,那么要注意JQKA的处理
for card in sorted(deck, key=spade_high): # deck是我们要进行排序的iterable,key=spade_high是排序依据
print(card)
# 这里的排序依据是一个函数,那么肯定是这样的:
# 将iterable的每一个元素作为参数传入这个函数,得到int类型的返回值,根据这个返回值来进行排序
# 由此可以推测,在spade_high函数体里的card其实是可迭代对象deck的元素。
# sorted接受两个参数
# arg1是需要进行排序的iterable
# arg2是一个函数,这个函数应该满足以下条件
# 参数是iterable arg1的element
# 返回值是element通过某种法则得到的int