FluentPython笔记0x04

p32

  • 和列表相比,元组除了无法修改其中的值以外,只有一处和列表不同:元组无法使用__reversed__,但是可以使用以下方法代替:

t = (1, 2, 3, 4)
print(tuple(reversed(t)))
  • 元组和列表可以与int型整数相乘,含义为返回对应的元组或列表,里边包括重复整数次的原来的元组或列表的内容。

p33

  • 像元组、列表等序列切片时为什么排除结束标号的项:1.可以简单的看出切片得到的长度,例range(3)以及my_list[:3];2.可以简单地计算切片长度,只需结束序号减去开始序号;3.可以只使用一个序号就能把序列切成两部分,例如my_list[:x]my_list[x:]

  • 切片的实现是一个切片类:slice(start, stop, step)。例:


source = '''
0.......8....12
0 AXL         5
1 August      6
2 key        10
'''
INDEX = slice(0, 2)
NAME = slice(2, 8)
POINT = slice(8, None)
line_items = source.split('\n')[2:]
for item in line_items:
  print(item[POINT], item[NAME])
  • 切片赋值操作:

l = list(range(10))
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
l[2:5] = [20, 30]
# [0, 1, 20, 30, 5, 6, 7, 8, 9]
del l[5:7]
# [0, 1, 20, 30, 5, 8, 9]
l[3::2] = [11, 22]
# [0, 1, 20, 11, 5, 22, 9]
l[2:5] = 100
# 错误,左面是列表右面对应应该也是列表等可迭代对象
l[2:5] = [100]
# [0, 1, 100, 22, 9]

p40

  • 有关修改元组中列表的问题:代码如下。

t = (1, 2, [30, 40])
t[2] += [50, 60]

终端报错如下

TypeError: 'tuple' object does not support item assignment

但是此时打印t会显示

(1, 2, [30, 40, 50, 60])

根据Python生成的字节码,元组+=这个操作的关键步骤为:1.将t[2]的值压栈(位于栈顶);2.执行栈顶值 += [50, 60],如果栈顶值不为可变变量的话会报错。但此处栈顶为list,故成功执行;3.执行t[2] = 栈顶值,如果t为不可变变量则会报错,此处t为元组故会出现报错。综上最终结果就是list的值改变了但是出现了报错。

总结:1.不建议在元组中填入可变项;2.自增不是原子操作,错误抛出可以在自增中的任何一个环节独立抛出,而不影响前面已执行的部分;3.如果遇到类似问题可以尝试阅读Python字节码,它并不难懂。

p42

  • list.sortsortedlist.sort只能用于可变序列,会改变列表,返回值为Nonesorted可以用于任何序列,它总是会返回一个新的序列而不改变原序列。

p44

  • 使用bisect进行有序序列的查找和插入:bisect即二分查找。

import bisect
import sys


HAYSTACK = [1, 4, 5, 6, 8, 12, 15, 20, 21, 23, 23, 26, 29, 30]
NEEDLES = [0, 1, 2, 5, 8, 10, 22, 23, 29, 30, 31]

ROW_FMT = '{0:2d} @ {1:2d}     {2}{0:2d}'


def demo(bisect_fn):
    for needle in reversed(NEEDLES):
        position = bisect_fn(HAYSTACK, needle)
        offset = position * '  |'
        print(ROW_FMT.format(needle, position, offset))


if __name__ == '__main__':
    if sys.argv[-1] == 'left':
        bisect_fn = bisect.bisect_left
    else:
        bisect_fn = bisect.bisect
    print('DEMO:', bisect_fn.__name__)
    print('haystack ->', ' '.join('%2d' % n for n in HAYSTACK))
    demo(bisect_fn)

其中bisect.bisectbisect.bisect_right是等价的,它们和bisect.bisect_left的区别在于遇到相等的值是插入的位置不同。一般情况下看不出区别,但是像11.0这样的还是有所区别的。

bisect.bisect有个有趣的应用:给连续的数值分级。


def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
  i = bisect.bisect(breakpoints, score)
  return grades[i]


print([grade(score) for score in [33, 99, 77, 70, 89, 90]])
# FACCBAA

此外,bisect.insort是向有序序列中插入值而不破坏有序,和bisect.bisect类似。

p48

  • 如果对序列有特殊需求,list不一定是最好的选择。例如,如果你想保存10M个浮点数,arraylist更加有效,因为array没有保存每一个float对象的全部。另外如果需要实现类似队列或者栈则可以使用deque

  • array需要先指定类型,即array只能存储一种类型的数据,但是这换来的是极大的性能提升。array.fromfilearray.tofile分别可以读取文件创建序列和将序列写入文件,这两种操作要比读写文本文件加上解析转换要快很多。以下为array支持的初始化类型:

类型码 C类型 Python类型 最小占用字节
c char character 1
b signed char int 1
B unsigned char int 1
u Py_UNICODE Unicode character 2
h signed short int 2
H unsigned short int 2
i signed int int 2
I unsigned int long 2
l signed long int 4
L unsigned long long 4
f float float 4
d double float 8

p51

  • memorview:内存查看对象,能够使用支持缓冲区协议的数据类型进行包装,在不需要复制的情况下用Python代码访问以及等大小修改。
Author: SinLapis
Link: http://sinlapis.github.io/2017/08/01/FluentPython笔记0x04/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.