序列修改,散列和切片

  • 基本序列协议:Basic sequence protocol: __len__ and __getitem__

本章通过代码讨论一个概念: 把protocol当成一个正式接口。协议概念和鸭子类型的关系。当创建自定义类型时,它的实际影响。


Vector类,一个自定义的序列类型

我们的实现Vector的策略是使用composition(组合),而不是继承。


10.3 序列和鸭子类型

协议是非正式的接口,只在文档内定义,在代码中不定义。

例如,序列协议在Python只需要__len__, __getitem__方法。任何类只要实现了这2个方法,它的实例就能当序列用。

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):
return len(self._cards) def __getitem__(self, position):
return self._cards[position]
>>> import linshi
>>> d = linshi.FrenchDeck()
>>> d
<linshi.FrenchDeck object at 0x1041796d0>
>>> len(d)
52
>>> d[0]
Card(rank='', suit='spades')

因为在FrenchDeck类中定义了序列协议的2个方法。所以它的实例就能使用序列类型的2个方法。

即使FrenchDeck类是Object的子类,但因为实现了序列协议,就可以把它当成一个序列类型。

这就是鸭子类型。拥有鸭子的行为,那么就把它当成鸭子。

protocols是非正式的非强制的,所以可以只实现一个协议的部分。

10.4可切片的序列

__getitem__实现了切片功能:

>>> d[0:2]
[Card(rank='', suit='spades'), Card(rank='', suit='spades')]

⚠️

但是,返回的是一个list,而不是FrenchDeck实例。因此就不能使用FrenchDeck的其他实例方法。

再考虑到那些内置序列类型,切片后返回的都是一个新的原本类型的实例,而不是其他类型。

所以,基于以上2点考虑,有时,根据需要,我们需要优化__getitem__方法中的代码,让返回值是原类的实例。

10.4.1 How Slicing Works

这是书中一个例子:

>>> class MySeq:
... def __getitem__(self, index):
... return index
...
>>> s = MySeq()
>>> s
<__main__.MySeq object at 0x104ea16d0>
>>> s[1]
1
>>> s[2]
2
>>> s[1:4]
slice(1, 4, None)
>>> s[1:4:1]
slice(1, 4, 1)
>>> s[1:4:2]
slice(1, 4, 2)
>>> s[1:4:2, 9]
(slice(1, 4, 2), 9)
>>> s[1:4:2, 7:9]
(slice(1, 4, 2), slice(7, 9, None))

本例子使用__getitem__直接返回传给它的值。

s[1:2]使用切片返回的是一个切片对象。因此s[1:2]传递给__getitem__的就是一个切片对象。

而,如果[]中有逗号,则返回的是一个tuple。即__getitem__接受到的是一个元祖。元祖可以包括多个切片。

再看一下slice类本身, 如何处理切片?

>>> slice
<class 'slice'>
# 为了省事,截取最后的属性
>>> dir(slice)[-4:]
['indices', 'start', 'step', 'stop']

这里有一个属性indices,  其实是index的复数型。

使用: help(slice.indices)可以得到相关解释。

indices(...)
S.indices(len) -> (start, stop, stride)

S代表一个slice对象。参数len代表原来要被切片的对象的长度。这是个内部方法。

被切片的对象,如:

"abcde"[:10:2], 但"abcde"的长度只有5,索引end = 10,超出了"abcde"的长度范围。因此会内部调用indices,处理超出边界的索引。

因此,"abcde"[:10:2]就会被内部处理变成"abcde"[0:5:2]。

>>> "abcde"[0:10:2]
  1. Python内部处理时,会生成一个slice(0, 10, 2),
  2. 然后使用slice(0, 10, 2).indices(len("abcde"))得到(0,5,2),即start, end ,stride三个slice属性。
  3. 最后调用"abcde"[0:5:2]得到切片的字符串"ace"

小结:

my_seq[a:b:c]背后的工作原理,就是创建slice(a, b, c)对象,然后交给__getitem__方法进行后续处理。返回符合Python风格的自定义类的实例。


后面的章节未阅读。

《流畅的Python》 Sequence Hacking, Hashing and Slicing(没完成)的更多相关文章

  1. [读书笔记]流畅的Python(Fluent Python)

    <流畅的Python>这本书是图灵科技翻译出版的一本书,作者Luciano Ramalho. 作者从Python的特性角度出发,以Python的数据模型和特殊方法为主线,主要介绍了pyth ...

  2. 《流畅的python》读书笔记

    流畅的python 第1章 python数据模型 ---1.1 一摞Python风格的纸牌 特殊方法,即__method__,又被称为魔术方法(magic method)或者双下方法(dunder-m ...

  3. 流畅的python(笔记)

    流畅的python中有很多奇技淫巧,整本书都在强调如何最大限度地利用Python 标准库.介绍了很多python的不常用的数据类型.操作.库等,对于入门python后想要提升对python的认识应该有 ...

  4. 流畅的python 对象引用 可变性和垃圾回收

    对象引用.可变性和垃圾回收 变量不是盒子 人们经常使用“变量是盒子”这样的比喻,但是这有碍于理解面向对象语言中的引用式变量.Python 变量类似于 Java 中的引用式变量,因此最好把它们理解为附加 ...

  5. 《流畅的Python》一副扑克牌中的难点

    1.现在在看<流畅的Python>这本书,看了三页就发现,这本书果然不是让新手来入门的,一些很常见的知识点能被这个作者玩出花来, 唉,我就在想,下面要分析的这些的代码,就算我费劲巴拉的看懂 ...

  6. 《流畅的Python》Object References, Mutability, and Recycling--第8章

    Object References, Mutability, and Recycling 本章章节: Variables Are Not Boxes identity , Equality ,  Al ...

  7. 《流畅的Python》 第一部分 序章 【数据模型】

    流畅的Python 致Marta,用我全心全意的爱 第一部分 序幕 第一章 Python数据模型 特殊方法 定义: Python解释器碰到特殊句法时,使用特殊方法激活对象的基本操作,例如python语 ...

  8. SyntaxError: Non-UTF-8 code starting with '\xbb' in file D:\流畅学python\ex32.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

    1. 报错如下: SyntaxError: Non-UTF-8 code starting with '\xd3' in file D:\流畅学python\ex34.py on line 4, bu ...

  9. 《流畅的Python》Data Structures--第2章序列array

    第二部分 Data Structure Chapter2 An Array of Sequences Chapter3 Dictionaries and Sets Chapter4 Text vers ...

随机推荐

  1. 写一个单独的qt模块 -- ongoing

    彩阳发的链接: https://wiki.qt.io/Creating_a_new_module_or_tool_for_Qt

  2. centos7配置hadoop

    hadoop压缩包下载: 链接:https://pan.baidu.com/s/1dz0Hh75VNKEebcYcbN-4Hw 提取码:g2e3 java压缩包下载: 链接:https://pan.b ...

  3. (二)javaweb开发的常见概念总结(来自那些年的笔记)

    目录 WEB开发相关知识 WEB服务器 Tomcat服务器 WEB应用程序 配置WEB应用 配置缺省的WEB应用 Web设置首页 web.xml文件 配置虚拟主机 配置https连接器 为我们的网站, ...

  4. Python开发【第二章】:深浅拷贝剖析

    Python深浅拷贝剖析 Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介绍一下这些概念之间的差别. 一.对象赋值 ...

  5. Scratch运动模块——有趣的弹球游戏(一)

    大家好!我是蓝老师,有了前几期Scratch的基础,相信大家早已摩拳擦掌,跃跃欲试了,甚至还有些小伙伴已经编写了非常不错的程序. 学习编程就是这样不断探索.主动思考.解决问题的过程. 本期内容: 课程 ...

  6. python处理Excel文件的几个模块

    在python中简单地处理excel文件,有几个相关的模块,各有千秋,本文将不定时收录. Python Excel网站收集了关于python处理excel文件的各种信息. [注意]使用python处理 ...

  7. Session和Cookie的原理

    1.session和cookie的存储 session一般保存在服务端文件中,php.ini中有个配置项--session.save_path='';这个里面填写的路径,将会使session文件保存在 ...

  8. 方法引用(method reference)

    目录 方法引用(method reference) 1. 含义 2. 分类 3. 总结 方法引用(method reference) 1. 含义 方法引用实际上是 Lambda 表达式的一种语法糖. ...

  9. 浅谈C++继承

    C++中的继承 1.继承概念及定义:     概念:是面向对象程序设计使代码可以复用的最重要的手段-----继承是类设计层次的复用     定义:            父类->基类:子类-&g ...

  10. C++虚函数【Java有虚函数吗?】

    1,简单介绍 定义在基类中的函数,子类必须对其进行覆写![必须对其进行覆写?!]——Java中的接口.Abstract方法中的抽象类也有这样的要求. C++中定义: virtual void deal ...