Python Data Model Part I - A Pythonic Card Deck

There should be one — and preferably only one — obvious way to do it.

Guido设计Python的宗旨之一就是每个功能都应该只对应唯一一个明确的操作。遵循这种设计规范,带来的好处就是各个库的一致性。比如说,当你尝试一个新的第三方数据结构时,想知道里面的元素有多少,大多数情况下你可以直接使用len(instance),而不是去猜测是不是count()size()之类的。如果你设计自己的集合类,也能提供标准的len()来返回实例中成员的数量,那么你设计的类已经开始有Pythonic类的样子了。按照类的设计规范设计的类是Pythonic,这样的规范也被称为Python data model。Python data model describes the API that you can use to make your own objects play well with the most idiomatic language features.

为了方便行文,我们不妨称自己设计的集合类叫做StandardCollection,创建一个StandardCollection实例sc。要是我们能通过sc[0]来访问第一个元素,那么StandardCollection又往Pythonic迈进了一大步。所以,究竟该如何让自己的类的len()和索引等操作符合规范的预期呢?在Java中,可以通过interface来规范开发者的设计,一个实现了某个接口的类,也要实现这个接口提供的方法。接口的方法便是一种设计规范,约定每个行为对应的方法调用。在python中也有类似的东西,他们被称作magic method或者是dunder method,基本形式是__func__,即函数名前后都带上两个下划线。如果想len(sc)返回sc中的元素个数, 就在StandardCollection类的定义中定义方法__len__(self)。如果希望通过数字索引来访问元素,就在StandardCollection类中定义方法__getitem__(self, index)

终于开始点题了,接下来我会展示一个Pythonic Card Deck类。他是一个扑克牌的集合类,里面含有52张牌(没有大小鬼)。为了让这个类变得Pythonic(一个集合类该有的操作都可以通过标准的操作来实现),我在方法中定义了__len____getitem__

import collections
from random import choice
Card = collections.namedtuple('Card', ['rank', 'suit'])
class Deck:
    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 = Deck()
print(len(deck)) # 52
print(deck[1]) # Card(rank='3', suit='spades')
print(deck[0:2]) # [Card(rank='2', suit='spades'), Card(rank='3', suit='spades')]
print(deck[0::13]) 
# randomly choose a card
print(choice(deck))
# iterator
for card in deck:
    print(card)

实现一个__getitem__方法可以给你带来很多好处:1)数字索引访问、2)随机访问、3)切片、4)迭代器。

注意__len__的使用条件,如果你定义了一个线段类Line,用len(line)来获取线段的长度是不对的。因为magic method __len__要求必须返回整数。所以,__len__ 主要是用在集合类上的,表示集合中元素的个数。 

虽然我标记这篇文章是原创,实际是以上内容都来自于Luciano Ramalho编著的《Fluent Python》。有天,realpython.com发了封订阅邮件给我,讲一个人抱怨python如何如何地糟糕。然而笔者的第一反应就是,自己作为一个资深的python爱好者,不允许别人如此偏颇地评价python。这样的自称真地触动到我了。自己作为程序员,无论是学什么语言,都是半斤八两。如果连在自己从事的行业中都是业余的,自己的人生是不是也是业余的,只是一个灵魂装到壳子里到这世上走一圈。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值