第二部分 Data Structure

  • Chapter2 An Array of Sequences
  • Chapter3 Dictionaries and Sets
  • Chapter4 Text versus Bytes

An Array of Sequences

本章讨所有的序列包括list,也讨论Python3特有的str和bytes。

也涉及,list, tuples, arrays, queues。

概览内建的序列

分类

Container swquences: 容器类型数据

  • list, tuple
  • collections.deque: 双向queue。

Flat sequences: 只存放单一类型数据

  • str,
  • bytes, bytearray, memoryview : 二进制序列类型
  • array.array:  array模块中的array类。一种数值数组。即只储存字符,整数,浮点数。

分类2:

Mutable sequences:

  • list, bytearray, array.array
  • collections.deque
  • memoryview

Immutable sequences:tuple, str, bytes

⚠️,内置的序列类型,并非直接从Sequence和MutableSequence这两个抽象基类(Abstract Base Class ,ABC)继承的。

了解这些基类,有助于我们总结出那些完整的序列类型包括哪些功能。

List Comprehensions and Generator Expressions

可以简写表示:listcomps, genexps。

例子:使用list推导式。

#
>>> symbols = '$¢£¥€¤'
>>> codes = [ord(symbol) for symbol in symbols]
>>> codes
[36, 162, 163, 165, 8364, 164]

ord(c)是把字符转化为Uicode对应的数值.

列表推导式的好处:

  • 比直接用for语句,更方便。也同样好理解。
  • 类似函数, 会产生局部作用域,不会再有变量泄露的问题。

map()和filter组合

symbols = '$¢£¥€¤'
beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))
print(beyond_ascii)

map(func, iterable) -> iterator

速度上list comprehensions更快。

Generator Expressions

Listcomps只能产生一个list,而genexps可以产生其他类型的序列。

它遵守迭代器协议,逐个产生元素。

例子,利用genexps产生tuple和array.array

symbols = '$¢£¥€¤'
a = tuple(ord(symbol) for symbol in symbols)
print(a) import array
arr = array.array("I", (ord(symbol) for symbol in symbols))
print(arr)
print(arr[0])
colors = ['black', 'white']
sizes = ['S', 'M', 'L']
a = ('%s %s' % (c, s) for c in colors for s in sizes)
print(a)
#产生一个生成器表达式<generator object <genexpr> at 0x10351b3c0>

⚠️函数生成器,要加yield关键字。


Tuples are not just Immutable lists

tuple除了是不可变数组/列表。

另有一个功能体现: 储存从数据库提取的一条记录:record, 但这个record没有field name,只有value。

例如:

traveler_ids = [('USA', ''), ('BRA', 'CE342567'),
('ESP', 'XDA205856')]
for passport in sorted(traveler_ids):
print('%s/%s' % passport) for country, _ in traveler_ids:
print(country)
#输出
BRA/CE342567
ESP/XDA205856
USA/31195855
USA
BRA
ESP

⚠️:_是一个占位符。

tuple unpacking

一个习惯用法产生的概念:

>>> lax_coordinates = (33.9425, -118.408056)
>>> latitude, longitude = lax_coordinates # tuple unpacking >>> latitude
33.9425
>>> longitude
-118.408056

下面的赋值代码省略了中间变量 :

>>>b,a=a,b
#等同于
x = (a, b)
b, a = x

这个概念也可以用到其他的类型上,如list。range(), dict。

>>> a, b, *rest = range(3)
>>> a, b, rest
(0, 1, [2])

⚠️使用*号抓起过多的item

有拆包,就有打包:

>>> o = 1
>>> n = 2
>>> o, n
(1, 2)

Nested Tuple Unpacking  嵌套tuple的解包

只要表达式左边的结构,符合嵌套元祖的结构,嵌套tuple也可以解包

>>> x = ('Tokyo','JP',36.933,(35.689722,139.691667))
>>> name, cc, pop, (latitude, longitude) = x
>>> name
'Tokyo'
>>> longitude
139.691667

Named Tuples --一个tuple的子类

具有tuple的方法,同时也有自己的方法和属性。

因为tuple具有拆包封包的特性,用起来很方便。

⚠️list拆包后,再封包,得到的是tuple类型。

>>> a = list(range(2))
>>> a
[0, 1]
>>> x,y = a
>>> x
0
>>> y
1
>>> x, y
(0, 1)
>>> z = x ,y
>>> z
(0, 1)

但是,如果把tuple类型用在一条数据库记录上:因为缺少fields字段。就很不方便,因此出现了Tuples类的子类named tuples。

使用工厂函数:collections.namedtuple(typename, field_names, *)

  • field_names可以是['x', 'y']也可以是"x, y, z"或"x y z"

下例子:创建一个子类City, 它的父类是tuple。即Ciyt.__bases__返回(<class 'tuple'>,)

from collections import namedtuple

Card = namedtuple("Card", ['rank', 'suit'])

City = namedtuple('City', '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))

⚠️内存一样

namedtuple和tuple的实例,占用的内存是一样的。因为namedtuple实例把字段名储存在了对应的类中。

因为结构固定,所以可以像dict一样显示key=value;

Tu = ('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
import sys
print(sys.getsizeof(tokyo))
print(sys.getsizeof(Tu))
#
#

类方法

_fields: 返回类的所有的field的名字。

>>> City._fields
('name', 'country', 'population', 'coordinates')

_asdict:返回一个对应field字段的dict:

print(tokyo._asdict())

#返回一个dict  {'name': 'Tokyo', 'country': 'JP', 'population': 36.933, 'coordinates': (35.689722, 139.691667)}

_make(): 接受一个可迭代对象来生成这个类的一个实例。等同于City(*tokyo)。

小结:

因为namedtuple的功能扩展,这个类就支持从数据库读取一条记录。但是因为是tuple的子类,不能对记录进行修改。


Slicing  --切片的高级用法

list, tuple, str这些sequences类都支持slicing。

Why Slices and Range Exclude the last Item?

就是习惯。真要找原因:

  •  my_list[:x] and my_list[x:]合起来就是my_list
  • a[:3], 直接清楚的表示这个切片包括3个item。
  • a[2:6], 6-2等于4。表示这个切片包括四个item。

Slice Objects

切片对象的用途:

一个有固定格式纯文本文件,需要对这个文件的每一行都进行相同的切片操作,那么使用Slice对象保存这种切片的起始位置和step。

之后无需反复重写切片了。

例子:

#invoice.txt
0.....6.................................40........52...55........
1909 Pimoroni PiBrella $17.50 3 $17.50
1489 6mm Tactile Switch x20 $4.95 2 $9.90
1510 Panavise Jr. - PV-201 $28.00 1 $28.00
#首先,读取文本文件的内容
with open('invoice.txt', 'r') as invoice:
line_items = invoice.read()
#然后,按照文本内的格式,创建3个切片对象,
sku = slice(0, 6)
description = slice(6, 40)
unit_price = slice(40, 52)
#最后,逐行打印切片的结果
for item in line_items.split('\n')[1:]:
print(item[unit_price], item[description])

直接使用切片对象的好处,方便代码的管理和维护。用自然语言描述要切片的字符串。

class slice(start=None, stop[, step=None])

返回一个slice对象。start,step默认为None。

slice对象有三个只读的数据属性(就是instance variable)start, stop, step

>>> a
slice(0, 6, None)
>>> type(a).__dict__.keys()
dict_keys(['__repr__', '__hash__', '__getattribute__', '__lt__', '__le__',
'__eq__', '__ne__', '__gt__', '__ge__', '__new__', 'indices', '__reduce__', 'start', 'stop', 'step', '__doc__'])
>>> a.start
0
>>> a.stop
6

给切片赋值

  • 可以给切片赋值,值必须是可迭代对象。替换原list中的元素。

  • 但如果切片start等于stop,则相当于插入了。

⚠️可参考源码(c写的)或这篇文章https://www.the5fire.com/python-slice-assignment-analyse-souce-code.html


Pythong, Ruby都支持对序列类型进行+和*操作

需要注意*操作对嵌套list:

>>> d = [[""]*3]*3
>>> d
[['', '', ''], ['', '', ''], ['', '', '']]
>>> d[1][1] = 's'
>>> d
[['', 's', ''], ['', 's', ''], ['', 's', '']] 

相当于:

>>> a = ['']*3
>>> a
['', '', '']
>>> b = [a]*3
>>> b
[['', '', ''], ['', '', ''], ['', '', '']]
>>> b[1][1] = "x"
>>> b
[['', 'x', ''], ['', 'x', ''], ['', 'x', '']]

⬆️例子,列表b,使用了3次a。b相当于[a, a, a]。


Augmented Assignment with Sequences  序列的增量赋值操作符 *=, +=

+=的背后是__iadd__方法,即(in-place addition,翻译过来就是,在当场进行加法运算,简单称为就地运算。)

这是因为a.+= b中的a 的内存地址不发生变化,所以称为就地运算。

⚠️但是,是否执行就地运算,要看type(a)是否包括__iadd__这个方法了。如果没有,则只相当于a = a + b, 新的a是一个新的对象。

  • 可变序列支持__iadd__
  • 不可变序列当然不支持了。比如tuple就不支持。
  • ⚠️str作为不可变序列,支持__iadd__,这是因为在循环内对str做+=太普遍了。因此对它做了优化,str实例初始化内存时预留了足够的空间,因此不会复制原有的字符串到新内存位置,
>>> l = list(range(3))
>>> l
[0, 1, 2]
>>> id(l)
4421232256
>>> l *= 2
>>> id(l)
4421232256

同样 *=及其他增量赋值操作符 都是这样。

关于+=的 Puzzler

>>> t = (1, 2, [30, 40])
>>> t[2] += [50,60]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [30, 40, 50, 60])

这个例子,完成了操作之后报告了❌。原因分析:

需要前置知识点:字节码,dis模块。 code object等知识。

模块dis:https://docs.python.org/zh-cn/3/library/dis.html  字节码反汇编器

什么是字节码?

字节码就是把可读的源码通过编译转化为bytecode,字节码还需要解释器才能转换为机器代码,所以字节码是一种中间代码。

操作系统都支持字节码转化,因此字节码可以用到不同系统中,通过转化为机器码直接在硬件上运行。

而且字节码也可以逐条执行。有了解释型语言的特点。

Python源代码会被编译成bytecode, 即Cpython解释器中表示Python程序的内部代码。它会缓存在.pyc文件(在文件夹__pycache__)内,这样第二次执行同一文件时速度更快。

具体见博文:https://www.cnblogs.com/chentianwei/p/12002967.html

再说上面的例子: dis.dis(x):反汇编x对象。

>>> dis.dis('s[a] += b')
1 0 LOAD_NAME 0 (s) #把s推入计算栈
2 LOAD_NAME 1 (a) #把a推入计算栈
4 DUP_TOP_TWO # 复制顶部的两个引用,无需从栈取出item
6 BINARY_SUBSCR #执行计算: TOS = TOS1[TOS], 即把s[a]的值推入计算栈(TOS代表栈的顶部), 现在栈里有3个item.
8 LOAD_NAME 2 (b) #把b推入栈
10 INPLACE_ADD #Tos = tos1+ tos, 即先从栈取出前2个item, 然后s[a] + b的结果推入栈。
12 ROT_THREE                # 将第2个,第三个栈项向上提升一个位置,栈顶部的项移动到第3个位置。
14 STORE_SUBSCR              # tos1[tos] = tos3
16 LOAD_CONST 0 (None)
18 RETURN_VALUE
 t[2] += [50,60]

当进行到上面

《流畅的Python》Data Structures--第2章序列array的更多相关文章

  1. 【Python学习笔记】Coursera课程《Python Data Structures》 密歇根大学 Charles Severance——Week6 Tuple课堂笔记

    Coursera课程<Python Data Structures> 密歇根大学 Charles Severance Week6 Tuple 10 Tuples 10.1 Tuples A ...

  2. 《Python Data Structures》Week5 Dictionary 课堂笔记

    Coursera课程<Python Data Structures> 密歇根大学 Charles Severance Week5 Dictionary 9.1 Dictionaries 字 ...

  3. 《Python Data Structures》 Week4 List 课堂笔记

    Coursera课程<Python Data Structures> 密歇根大学 Charles Severance Week4 List 8.2 Manipulating Lists 8 ...

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

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

  5. 《流畅的Python》第二部分 数据结构 【序列构成的数组】【字典和集合】【文本和字节序列】

    第二部分 数据结构 第2章 序列构成的数组 内置序列类型 序列类型 序列 特点 容器序列 list.tuple.collections.deque - 能存放不同类型的数据:- 存放的是任意类型的对象 ...

  6. Python实验报告——第4章 序列的应用

    实验报告 [实验目的] 1.掌握python中序列及序列的常用操作. 2.根据实际需要选择使用合适的序列类型. [实验条件] 1.PC机或者远程编程环境. [实验内容] 1.完成第四章 序列的应用 实 ...

  7. 流畅的python学习笔记:第二章

    第二章开始介绍了列表这种数据结构,这个在python是经常用到的结构 列表的推导,将一个字符串编程一个列表,有下面的2种方法.其中第二种方法更简洁.可读性也比第一种要好 str='abc' strin ...

  8. 流畅的python学习笔记:第一章

    这一章中作者简要的介绍了python数据模型,主要是python的一些特殊方法.比如__len__, __getitem__. 并用一个纸牌的程序来讲解了这些方法 首先介绍下Tuple和nametup ...

  9. 《流畅的Python》 A Pythonic Object--第9章

    Python的数据模型data model, 用户可以创建自定义类型,并且运行起来像内建类型一样自然. 即不是靠继承,而是duck typing. 支持用内建函数来创建可选的对象表现形式.例如repr ...

随机推荐

  1. 最新 第一视频java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.第一视频等10家互联网公司的校招Offer,因为某些自身原因最终选择了第一视频.6.7月主要是做系统复习.项目复盘.Leet ...

  2. Vue Router路由管理器介绍

    参考博客:https://www.cnblogs.com/avon/p/5943008.html 安装介绍:Vue Router 版本说明 对于 TypeScript 用户来说,vue-router@ ...

  3. Ie浏览器请求400错误,谷歌火狐等浏览器正常请求.

    做项目的时候,遇到一个小的问题.一个location.href="请求的url"在其它浏览器上是可以正常请求的.但是在ie浏览器上确出现奇怪的http请求400错误,我们先来对于h ...

  4. eNSP——利用三层交换机实现VLAN间路由

    原理: VLAN将一个物理的LAN在逻辑上划分成多个广播域.VLAN内的主机间可以直接通信,而VLAN间不能直接互通. 在现实网络中,经常会遇到需要跨VLAN相互访问的情况,工程师通常会选择一些方法来 ...

  5. CentOS使用yum安装jdk

    1.查看系统版本命令 cat /etc/issue 2.查看yum包含的jdk版本 yum search java 或者 yum list java* 版本 jre jdk 1.8 java-1.8. ...

  6. 乐字节Java反射之三:方法、数组、类加载器和类的生命周期

    本文承接上一篇:乐字节Java发射之二:实例化对象.接口与父类.修饰符和属性 继续讲述Java反射之三:方法.数组.类加载器 一.方法 获取所有方法(包括父类或接口),使用Method即可. publ ...

  7. MakeFile文件是什么——内容、工作原理、作用、使用

    MakeFile文件是什么?它里面包含什么内容.具有什么作用.怎么使用?下面就来具体说说. 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你 ...

  8. electron实现透明点投的方法

    1. electron createWindow 的时候 设置 transparent: true, clickThrough: 'pointer-events' 2. body 上添加 pointe ...

  9. MySQL5.7主从同步配置

    主从同步,将主服务器(master)上的数据复制到从服务器(slave). 应用场景 读写分离,提高查询访问性能,有效减少主数据库访问压力. 实时灾备,主数据库出现故障时,可快速切换到从数据库. 数据 ...

  10. 点标记(lambda表达式+linq查询标记符)与linq语句(查询表达式)

    什么是Linq表达式?什么是Lambda表达式? 参照:https://www.cnblogs.com/zhaopei/p/5746414.html