python日课1-1:一摞有序的纸牌

《流畅的python》 第一章 示例1-1

特殊方法

python解释器碰到特殊的句法时,会使用特殊方法去激活一些基本的对象操作,这些特殊方法的名字以以两个下划线开头,以两个下划线结尾的方法:__init____len____getitem__
这些特殊方法名能让自己的对象实现和支持以下的语言架构,并与之交互:

  • 迭代
  • 集合类
  • 属性访问
  • 运算符重载
  • 函数和方法的调用
  • 对象的创建和销毁
  • 字符串表示形式和格式化
  • 管理上下文(即with块)

示例1-1

import collections
from random import choice

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, item):
        return self._cards[item]

    def choice(self):
        return choice(self._cards)

首先用**collections.namedtuple** 构建了一个简单的类来表示一张纸牌。自python2.6,namedtuple就加入到python,用以构建只有少数属性但是没有方法的对象。

beer_card = Card('7', 'diamonds')
print(beer_card)

输出:

Card(rank=‘7’, suit=‘diamonds’)

可以使用len()来参考一叠牌有多少张,抽取特定的一张纸牌(比如第一张、最后一张)

deck = FrenchDeck()
print(len(deck))
print(deck[0])
print(deck[-1])
print('------------------------------------')

输出:

52
Card(rank=‘2’, suit=‘spades’)
Card(rank=‘A’, suit=‘hearts’)

Python已经内置了从一个序列中随机选出一个元素的函数random.choice

print(deck.choice())
print(deck.choice())
print(deck.choice())

输出:

Card(rank=‘8’, suit=‘hearts’)
Card(rank=‘6’, suit=‘clubs’)
Card(rank=‘10’, suit=‘clubs’)

切片操作

__getitem__[]操作交给了self._cards列表,所以deck类自动支持切片操作。

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

输出:

[Card(rank=‘2’, suit=‘spades’), Card(rank=‘3’, suit=‘spades’), Card(rank=‘4’, suit=‘spades’)]
[Card(rank=‘A’, suit=‘spades’), Card(rank=‘A’, suit=‘diamonds’), Card(rank=‘A’, suit=‘clubs’), Card(rank=‘A’, suit=‘hearts’)]

迭代
for card in deck:
    print(card)

反向迭代:

for card in reversed(deck):
    print(card)

隐式迭代:in运算符会按顺序做一次迭代搜索

print(Card('Q', 'hearts') in deck)

输出:

True

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


def spades_high(self):
    rank_value = FrenchDeck.ranks.index(self.rank)
    return rank_value * len(suit_values) + suit_values[self.suit]


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

输出:

Card(rank=‘2’, suit=‘clubs’)
Card(rank=‘2’, suit=‘diamonds’)
Card(rank=‘2’, suit=‘hearts’)
Card(rank=‘2’, suit=‘spades’)
Card(rank=‘3’, suit=‘clubs’)
。。。。。。。。。。。。。

如何使用特殊方法

特殊方法的存在是为了被python解释器调用的,你自己并不需要调用它们。
在执行len(deck)的时候,deck是一个自定义类的对象,python会自己去调用由你实现的__len__方法。

如果是python内置的类型,比如列表(list)、字符串(str)、字节序列(bytearray)等,那么CPython会抄个近路,__len__实际上会直接返回PyVarObject里的ob_size属性。直接读取这个值比调用一个方法要快很多。

很多时候,特殊方法的调用是隐式的,比如 for i in x:这个语句,背后其实用的是iter(x),而这个函数的背后则是x.__iter__()(前提是这个方法在x中被实现了)。

通常你的代码无需直接使用特殊方法。

通过内置的函数(len、iter、str等)来使用特殊方法是最好的选择。

不要自己想当然的随意添加特殊方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值