Fluent Python示例代码解析:FrenchDeck类的数据模型实现

Fluent Python示例代码解析:FrenchDeck类的数据模型实现

example-code-2e Example code for Fluent Python, 2nd edition (O'Reilly 2022) example-code-2e 项目地址: https://gitcode.com/gh_mirrors/ex/example-code-2e

理解FrenchDeck的设计理念

在《Fluent Python》第二版的示例代码中,FrenchDeck类展示了一个优雅的Python数据模型实现。这个类模拟了一副标准的法国扑克牌(52张),通过实现特殊方法(magic methods)来提供类似序列的行为,而无需显式地继承自任何序列类型。

核心组件分析

Card类:扑克牌的基本单元

>>> beer_card = Card('7', 'diamonds')
>>> beer_card
Card(rank='7', suit='diamonds')

Card类是一个简单的数据类,包含两个属性:

  • rank:牌面值('2'到'A')
  • suit:花色('spades', 'hearts', 'diamonds', 'clubs')

FrenchDeck类:完整的扑克牌组

>>> deck = FrenchDeck()
>>> len(deck)
52

FrenchDeck类通过实现__len__特殊方法,使得我们可以直接使用len()函数获取牌组中牌的数量。

序列操作演示

FrenchDeck实现了序列协议,因此支持各种序列操作:

切片操作

>>> deck[:3]
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]

获取前3张牌(黑桃2、黑桃3、黑桃4)

步长切片

>>> deck[12::13]
[Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]

从第13张开始,每隔13张取一张(获取所有A牌)

成员检查

>>> Card('Q', 'hearts') in deck
True
>>> Card('Z', 'clubs') in deck
False

通过实现__contains__方法,支持in操作符检查某张牌是否在牌组中

迭代能力

FrenchDeck实现了迭代协议:

正向迭代

>>> for card in deck:  # doctest: +ELLIPSIS
...   print(card)
Card(rank='2', suit='spades')
Card(rank='3', suit='spades')
Card(rank='4', suit='spades')
...

反向迭代

>>> for card in reversed(deck):  # doctest: +ELLIPSIS
...   print(card)
Card(rank='A', suit='hearts')
Card(rank='K', suit='hearts')
Card(rank='Q', suit='hearts')
...

带索引的迭代

>>> for n, card in enumerate(deck, 1):  # doctest: +ELLIPSIS
...   print(n, card)
1 Card(rank='2', suit='spades')
2 Card(rank='3', suit='spades')
3 Card(rank='4', suit='spades')
...

自定义排序

示例中还展示了如何为扑克牌定义自定义排序规则:

>>> 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]

排序规则说明:

  1. 按花色权重排序:黑桃(3) > 红心(2) > 方块(1) > 梅花(0)
  2. 同花色按牌面值排序(2最小,A最大)

排序测试

>>> spades_high(Card('2', 'clubs'))
0
>>> spades_high(Card('A', 'spades'))
51

应用排序

>>> for card in sorted(deck, key=spades_high):  # doctest: +ELLIPSIS
...      print(card)
Card(rank='2', suit='clubs')
Card(rank='2', suit='diamonds')
Card(rank='2', suit='hearts')
...
Card(rank='A', suit='diamonds')
Card(rank='A', suit='hearts')
Card(rank='A', suit='spades')

设计模式总结

FrenchDeck类展示了Python数据模型的强大之处:

  1. 通过实现特殊方法(__len__, __getitem__等)来获得Python核心语言特性的支持
  2. 无需继承,通过实现协议来获得序列行为
  3. 利用Python内置函数(len(), reversed(), sorted()等)来增强功能
  4. 保持代码简洁的同时提供丰富的功能

这种设计模式是Pythonic编程的典范,体现了"鸭子类型"的思想——只要对象实现了适当的协议,就可以像特定类型的对象一样使用。

example-code-2e Example code for Fluent Python, 2nd edition (O'Reilly 2022) example-code-2e 项目地址: https://gitcode.com/gh_mirrors/ex/example-code-2e

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈冉茉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值