第2章 序列构成的数组

本章讨论的内容是序列类型

2.1 内置序列类型概览

根据存储数据类型分类

容器序列: 能存放不同类型的数据

​ list, tuple, collections.deque

扁平序列:只能容纳一种类型

​ str, bytes, byte array, memoryview, array.array

根据是否被修改分类

可变类型

​ list, byte array, array.array, collections.deque, memoryview

不可变类型

​ tuple, str, bytes

2.2 列表推导和生成器表达式

2.2.1 列表推导和可读性

# 字符串变成unicode码
symbols = '$¢£¥€¤'
codes = []
for symbol in symbols:
  codes.append(ord(symbol))
  
  
# 列表推导式写法
codes = [ord(symbol) for symbol in symbols]

NOTE:列表推导不会再有变量泄漏的问题

在这里插入图片描述

2.2.2 列表推导同filter和map的比较

symbols = '$¢£¥€¤'
# 列表推导
beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]
# map/filter
beyond_ascii = list(filter(lambda c: c>127, map(ord, symbols)))

2.2.3 笛卡尔积

colors = ['black', 'white']
sizes = ['S', 'M', 'L']
tshirts = [(color, size) for color in colors for size in sizes]

2.2.4 生成器表达式

生成器表达式的语法跟列表推导差不多,只不过是方括号换成圆括号而已

symbols = '$¢£¥€¤'
# 生成器推导
beyond_ascii = (ord(s) for s in symbols if ord(s) > 127)

colors = ['black', 'white']
sizes = ['S', 'M', 'L']
tshirts = ((color, size) for color in colors for size in sizes)

2.3 元组不仅仅是不可变的列表

2.3.1 元组和记录

元组可以对数据记录,每个元素记录了字段的数据

city, year, pop, chg, area = ('Tokyo', 2003, 32450, 0.66, 8014)

2.3.2 元组拆包

lax_coordinates = (33.9425, -118.408056)
latitude, longitude = lax_coordinates # 元组拆包

# 用*来处理剩下的元素
a, b, *rest=range(5)

关于拆包,可以参考可迭代元素拆包

2.3.3 嵌套元组拆包

metro_areas = [
  ('Tokyo','JP',36.933,(35.689722,139.691667)), 
  ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)), 
  ('Mexico City', 'MX', 20.142, (19.433333, -99.133333))
]
# 嵌套元组拆包
for name, cc, pop, (latitude, longitude) in metro_areas:
	if longitude <= 0:
		print(fmt.format(name, latitude, longitude))

2.3.4 具名元组

collections.namedtuple: 用来构建只有少数属性但是没有方法的对象

_fields属性:包含这个类所有字段名称的元组

_make : 接收可迭代对象生成类实例,作用类似City(*delhi_data)

_asdict: 具名元组以collections.OrderedDict形式返回

>>> from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates')
>>> City._fields
>>> LatLong=namedtuple('LatLong', 'lat long')
>>> delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
>>> delhi = City._make(delhi_data)
>>> delhi._asdict()
OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935), ('coordinates', LatLong(lat=28.613889, long=77.208889))])

2.3.5 作为不可变列表的元组

较之list, 除了增减元素相关的方法以外,元组支持列表的其他所有方法

2.4 切片

2.4.1 为什么切片和区间会忽略最后一个元素

  1. 通过最后一个位置信息,快速看出切片和区间有几个元素:range(3)和my_list[:3]都返回3个元素
  2. 当起止位置信息都可见时,快速计算切片和区间的长度,下标(stop-start)即可
  3. my_list[:x]和my_list[x:] 分割成不重叠的两部分

2.4.2 对对象进行切片

>>> s = 'bicycle'
>>> s[::3]
'bye'

2.4.3 多维切片和省略

多维切片:见2.9.3 Numpy

省略:Ellipsis

2.4.4 给切片赋值


>>> l = list(range(10))
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l[2:5] = [20, 30]
>>> l
[0, 1, 20, 30, 5, 6, 7, 8, 9]
>>> del l[5:7]
>>> l
[0, 1, 20, 30, 5, 8, 9]
>>> l[3::2] = [11, 22]
>>> l
[0, 1, 20, 11, 5, 22, 9]
# 如果赋值的对象时一个切片,那么赋值语句右侧必须是可迭代对象
>>> l[2:5] = 100 
Traceback (most recent call last):
       File "<stdin>", line 1, in <module>
     TypeError: can only assign an iterable
>>> l[2:5] = [100]
>>> l
[0, 1, 100, 22, 9]

2.5 对序列使用+和*

+和* 不修改原有的操作对象,而是构建一个全新的序列

>>> board = [['_'] * 3 for i in range(3)]
>>> board
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] >>> board[1][2] = 'X' 
>>> board
[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]

下列是经常遇到的错误,对同一对象的引用的列表

>>> weird_board = [['_'] * 3] * 3 
>>> weird_board
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] >>> weird_board[1][2] = 'O'
>>> weird_board
[['_', '_', 'O'], ['_', '_', 'O'], ['_', '_', 'O']]

2.6 序列的增量赋值

>>> a += b 在这个表达式中,变量名会不会关联到新的对象,取决于__iadd__方法是否实现

  • 如果a实现了__iadd__方法,就调用这个方法。对可变序列(例如list, bytearray, array.array)来说, a会就地改动,就像调用了a.extend(b)
  • 如果没有实现__iadd__方法,a+=b这个表达式的效果就等效a=a+b;首先计算a+b,得到新的对象,然后赋值给a
>>> l = [1, 2, 3] 
>>> id(l) 4311953800
>>> l *= 2
>>> l
[1, 2, 3, 1, 2, 3] 
>>> id(l) 4311953800
>>> t = (1, 2, 3) 
>>> id(t) 4312681568
>>> t *= 2
>>> id(t) 4301348296

str 不适用上述规则,因为对字符串+=太普遍,CPython对它做了优化,为str初始化内存的时候,程序预留了额外了可扩展空间,增量操作,不会涉及复制原有字符到新位置的操作。

2.7 list.sort方法和内置函数sorted

Python 的一个惯例:如果一个函数或者方法对对象进行的是就地改动,那它就应该返回None,好让调用者知道传入的参数发生了变动,而且并未产生新的对象

list.sort: 就地排序列表,不会新建列表

sorted:新建列表作为返回值

>>> fruits = ['grape', 'raspberry', 'apple', 'banana'] 
>>> sorted(fruits)
['apple', 'banana', 'grape', 'raspberry'] 
>>> fruits
['grape', 'raspberry', 'apple', 'banana'] 
>>> fruits.sort() 
>>> fruits
['apple', 'banana', 'grape', 'raspberry'] 

2.8 用bisect来管理已排序的序列

2.8.1 用bisect来搜索

分为bisect.bisect (bisect_right别名), bisect.bisect_left

import bisect
import sys

HAYSTACK=[1,4,5,23,23,26,29,30]
postion=bisect.bisect(HAYSTACK, 23)
print(postion)
postion=bisect.bisect_left(HAYSTACK, 23)
print(postion)
#结果:
5
3

2.8.2 用bisect.insort插入新元素

import bisect
import sys

my_list=[1,4,5,26,29,30]
bisect.insort(my_list, 23)
print(my_list)

# 结果
[1, 4, 5, 23, 26, 29, 30]

2.9 当列表不是首选时

2.9.1 数组

一个浮点型数据的创建,存入文件和从文件读取的过程

from array import array
from random import random 
floats=array('d', (random() for i in range(10**7)))
floats[-1]
# 0.10839796787230571

fp=open('floats.bin', 'wb')
floats.tofile(fp)
fp.close()
floats2=array('d')
fp=open('floats.bin', 'rb')
floats2.fromfile(fp, 10**7)
fp.close()
floats2[-1]
# 0.10839796787230571

floats2==floats
# True

2.9.2 内存视图

通过改变数组中的一个字节来更新数组里某个元素的值

import array
numbers=array.array('h', [-2, -1, 0, 1, 2])
memv=memoryview(numbers)
len(memv)
# 5
memv[0]
# -2
memv_oct=memv.cast('B')
memv_oct.tolist()
# [254, 255, 255, 255, 0, 0, 1, 0, 2, 0]

2.9.3 NumPy和SciPy

对numpy.ndarray的行和列进行基本操作

import numpy
a=numpy.arrange(12)
# array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
a.shape=3,4
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

2.9.4 双向队列和其他形式的队列

  • collections.deque线程安全

    ​ 快速从两端添加或删除的数据类型

    from collections import deque
    dq=deque(range(10), maxlen=10)
    dq
    # deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
    dq.rotate(3)
    dq
    # deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
    dq.extend([11, 22, 33])
    dq
    # deque([0, 1, 2, 3, 4, 5, 6, 11, 22, 33], maxlen=10)
    
  • queue:

    ​ 线程安全类Queue, LifoQueue, PriorityQueue

  • multiprocessing:

    ​ Queue设计给进程通信用的

    ​ multiprocessing.JoinableQueue类型为任务管理提供便利

  • asyncio:

    ​ Queue, LifoQueue, PriorityQueue, JoinableQueue,受queue和multiprocessing模块影响,为异步编程的任务管理提供便利

  • heapq:

    ​ 没有队列类,提供了heappush和heappop方法,可以把可变队列当作堆队列或优先队列使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值