威尼斯人线上娱乐

python学习笔记,数据结构

28 3月 , 2019  

正文重要内容

  种类类型分类:

    (1)容器种类、扁平系列

    (2)可变类别、不可变种类

  列表推导式

  生成器表明式

  元组拆包

  切片

  排序(list.sort方法和sorted函数)

  bisect

 

python高级——目录

  文中代码均位居github上:https://github.com/ampeeg/cnblogs/tree/master/python高级

 

python高级(二)—— python内置类别类型,python内置连串类型

python类别类型

队列构成的数组

内置类别类型大概浏览

Python
标准库用 C 完毕了拉长的队列类型,列举如下:

容器连串

  list、tuple
和 collections.deque 这个类别能存放差别类别的数量

扁平体系

  str、bytes、bytearray、memoryview
和 array.array,那类类别只好容纳一种档次

注:

  容器种类存放的是它们所蕴藏的即兴档次的靶子的引用,而扁平系列里存放的是值而不是引用。换句话说,扁平类别其实是一段连接的内部存款和储蓄器空间。不问可见扁平类别其实更是严刻,然而它当中只可以存放诸如字符、字节和数值那种基础项目。

队列类型仍是能够依照是不是被涂改来分类:

可变连串

  list、bytearray、array.array、collections.deque
和memoryview

不足变类别

  tuple、str
和 bytes

 

列表推导和生成器表达式

  列表推导是构建列表(list)的快捷格局,而生成器表明式则能够用来创制其余任何项指标类别。如若你的代码里并不常常使用它们,那么很恐怕您错过了过多写出可读性更好且更高效的代码的空子。

举个🌰

 1 '''
 2 需求:把一个字符串变成 Unicode 码位的列表
 3 '''
 4 
 5 #普通的写法
 6 symbols = '$¢£¥€¤'
 7 codes = []
 8 for symbol in symbols:
 9     codes.append(ord(symbol))
10 else:
11     print('普通写法得到的codes:', codes)
12 
13 #列表推倒式的写法
14 codes = [ord(symbol) for symbol in symbols]
15 print('列表推倒式写法得到的codes:', codes)

  列表推导能够扶持大家把二个连串或是别的可迭代类型中的成分过滤或是加工,然后再新建七个列表。Python
内置的 filter 和 map
函数组合起来也能达到规定的标准那百分之十效,但是可读性上打了十分大的折扣。

  

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

  filter
和 map
合起来能做的业务,列表推导也得以做,而且还不需求借助难以通晓和读书的
lambda 表明式

 1 #普通列表推到式实现过滤功能
 2 symbols = '$¢£¥€¤'
 3 beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]
 4 print('普通列表推倒式过滤后的结果:', beyond_ascii)
 5 
 6 #使用filter函数实现的效果
 7 beyond_ascii_filter = list(filter(lambda s: s > 127, map(ord, symbols)))
 8 print('使用filter高阶函数实现过滤的结果:', beyond_ascii_filter)
 9 
10 print(beyond_ascii == beyond_ascii_filter)

 

笛卡儿积

  用列表推导能够生成多少个或上述的可迭代类型的笛卡儿积。笛卡儿积是二个列表,列表里的要素是由输入的可迭代类型的成分对构成的元组,因而笛卡儿积列表的长度等于输入变量的长度的乘积,如图:

威尼斯人线上娱乐 1

 

图:含有
4 种花色和 3 种牌面包车型客车列表的笛卡儿积,结果是3个富含 10个因素的列表

 

假定你须求一个列表,列表里是
3 种分裂尺寸的 T 恤衫,每一种尺寸都有三个颜色,用列表推导算出了那些列表,列表里有 6 种组成:

笛Carl乘积的:

 1 '''
 2 需求:如果你需要一个列表,列表里是 3 种不同尺寸的 T 恤衫,每个尺寸都有2个颜色,用列表推导算出了这个列表,列表里有6种组合
 3 '''
 4 
 5 colors = ['black', 'white']
 6 sizes = ['S', 'M', 'L']
 7 
 8 tshirts = [(size, color) for size in sizes for color in colors]
 9 print('T恤巴拉巴拉的~:', tshirts)
10 
11 #循环列表输出每种可能性
12 for shirt in tshirts:
13     print(shirt)

上述代码执行的结果为:

T恤巴拉巴拉的~: [('S', 'black'), ('S', 'white'), ('M', 'black'), ('M', 'white'), ('L', 'black'), ('L', 'white')]
('S', 'black')
('S', 'white')
('M', 'black')
('M', 'white')
('L', 'black')
('L', 'white')

 

生成器表明式

  纵然也可以用列表推导来开端化元组、数组或别的系列类型,但是生成器表明式是更好的选料。那是因为生成器表达式背后遵从了迭代器协议,能够每个地冒出成分,而不是先创立一个完好无缺的列表,然后再把这一个列表传递到有个别构造函数里。前边那种办法显著能够节本省部存储器。

  用生成器表明式初叶化元组和数组:

1 symbols = '$¢£¥€¤'
2 r = tuple(ord(s) for s in symbols)
3 print('利用生成器初始化元祖:', r)
4 
5 import array
6 
7 a = array.array('I', (ord(symbol) for symbol in symbols))
8 print(a)

以上代码执行的结果为:

利用生成器初始化元祖: (36, 162, 163, 165, 8364, 164)
array('I', [36, 162, 163, 165, 8364, 164])

注意:

  1. 设若生成器表明式是一个函数调用进程中的唯一参数,那么不必要分外再用括号把它围起来。
  2. array
    的构造方法必要五个参数,因而括号是必不可少的。array
    构造方法的首先个参数钦命了数组中数字的囤积格局。

  大家关系过的
T 恤衫的 2 种颜色和 3 种尺码的拥有结成。与示例
2-4不等的是,用到生成器表达式之后,内部存款和储蓄器里不会留下三个有 伍个结合的列表,因为生成器表明式会在历次 for
循环运维时才生成3个结合。倘若要计算五个各有 1000个成分的列表的笛卡儿积,生成器表明式就能够帮忙省掉运转 for
循环的支出,即3个暗含 100 万个成分的列表。

  使用生成器完成笛Carl乘积:

1 colors = ['black', 'white']
2 sizes = ['S', 'M', 'L']
3 
4 for tshirt in ('%s %s'%(color, size) for color in colors for size in sizes):
5     print(tshirt)

上述代码执行的结果为:

black S
black M
black L
white S
white M
white L

 

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

  有些Python
入门教程把元组称为“不可变列表”,然则那并不曾完全总结元组的性状。除了作为不可变的列表,它仍可以够用于没有字段名的记录。鉴于后者日常被忽略,大家先来探视元组作为记录的成效。

元组和著录

  元组其实是对数码的笔录:元组中的种种成分都存放了笔录中一个字段的数额,外加那一个字段的职务。正是以此任务音信给多少给予了意义。

举个
把元组用作记录

 1 lax_coordinates = (33.9425, -118.408056)
 2 
 3 #解包,把元祖中的元素对应的索引对应成变量
 4 city, year, pop, chg, area = ('Tokyo', 2003, 32450, 0.66, 8014)
 5 
 6 traveler_ids = [('USA', '31195855'), ('BRA', 'CE342567'), ('ESP', 'XDA205856')]
 7 for passport in sorted(traveler_ids):
 8     print('%s/%s' % passport)
 9 
10 #元祖中的元素又是一个单独的元祖,可以通过解包的方式循环,不需要的数据可以通过_占位符来代替
11 for country, _ in traveler_ids:
12     print(country)

威尼斯人线上娱乐,上述代码执行的结果为:

BRA/CE342567
ESP/XDA205856
USA/31195855
USA
BRA
ESP

元组拆包

  大家把元组
(‘Tokyo’, 二〇〇四, 32450, 0.66, 8014) 里的要素分别赋值给变量
city、year、pop、chg 和
area,而那全部的赋值大家只用一行评释就写完了。同样,在后头一行中,3个 %
运算符就把 passport 元组里的成分对应到了 print
函数的格式字符串空档中。那多个都以对元组拆包的行使。

注意:

  元组拆包能够采纳到其余可迭代对象上,唯一的硬性须求是,被可迭代对象中的成分数量必须要跟接受那几个成分的元组的空档数一致。除非大家用 * 来代表忽略多余的要素,在“用
* 来处理多余的因素”一节里,小编会讲到它的实际用法。Python
爱好者们很喜爱用元组拆包这么些说法,不过可迭代成分拆包那么些表明也慢慢流行了四起,比如“PEP
3132—Extended IterableUnpacking”(

拆包的写法:

1 lax_coordinates = (33.9425, -118.408056)
2 latitude, longitude = lax_coordinates #拆包
3 
4 print('latitude:', latitude)
5 print('longitude:', longitude)

其它一个很优雅的写法当属不选用当中变量调换四个变量的值:

b, a = a, b

还足以用
* 运算符把三个可迭代对象拆开作为函数的参数:

>>> divmod(20, 8)
(2, 4)
>>> t = (20, 8)
>>> divmod(*t)
(2, 4)
>>> quotient, remainder = divmod(*t)
>>> quotient
2
>>> remainder
4

平行赋值栗子:

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

在平行赋值中,*
前缀只可以用在一个变量名前面,不过那么些变量能够出现在赋值表达式的肆意地点:

>>> a, *body, c, d = range(5)
>>> a, body, c, d
(0, [1, 2], 3, 4)
>>> *head, b, c, d = range(5)
>>> head, b, c, d
([0, 1], 2, 3, 4)

嵌套元组拆包

  接受表明式的元组可以是嵌套式的,例如
(a, b, (c,
d))。只要那一个接受元组的嵌套结构适合表明式自身的嵌套结构,Python
就能够作出正确的对应。

 1 #每个组内对应四个元素,其中最后一个元素为一对坐标点
 2 metro_areas = [
 3     ('Tokyo','JP',36.933,(35.689722,139.691667)),
 4     ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
 5     ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
 6     ('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
 7     ('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
 8 ]
 9 #{}format的格式化占位符,:15是十五个宽度 ^9居中对齐九个宽度
10 print('{:15} | {:^9} | {:^9}'.format('', 'lat', 'long.'))
11 fmt = '{:15} | {:9.4f} | {:9.4f}'
12 
13 for name, cc, pop, (latitude, longitude) in metro_areas:
14     #这个条件判断把输出限制在西半球的城
15     if longitude < 0:
16         print(fmt.format(name, latitude, longitude))

python学习笔记,数据结构。如上代码执行的结果为:

                |    lat    |   long.  
Mexico City     |   19.4333 |  -99.1333
New York-Newark |   40.8086 |  -74.0204
Sao Paulo       |  -23.5478 |  -46.6358

取名元祖

  collections.namedtuple
是多个工厂函数,它能够用来创设四个带字段名的元组和叁个盛名字的类——这么些带名字的类对调试程序有十分的大帮扶。

举个
定义和使用命名元组

 1 from collections import namedtuple
 2 
 3 '''
 4 创建一个命名元祖,需要两个参数,第一个是类名称,另外的是类各个字段的名称,
 5 后者可以是由数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串
 6 '''
 7 City = namedtuple('City', 'name country population coordinates')
 8 
 9 #存放在对应字段里的数据要以一串参数的形式传入到构造函数中
10 tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
11 
12 #通过字段或者是索引来获取值
13 print(tokyo)
14 print(tokyo.name)
15 print(tokyo.population)
16 print(tokyo.coordinates)
17 print(tokyo[1])

  除了从屡见不鲜元组那里继承来的性质之外,具名元组还有部分要好专有的习性。示例
2-10 中就突显了多少个最得力的:_fields 类属性、类方法_make(iterable)
和实例方法 _asdict()。

1 print(City._fields)
2 
3 LatLong = namedtuple('LatLong', 'lat long')
4 delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
5 #用_make() 通过接受一个可迭代对象来生成这个类的一个实例,它的作用跟 City(*delhi_data)是一样的
6 delhi = City._make(delhi_data)
7 
8 #_asdict() 把具名元组以 collections.OrderedDict 的形式返回,我们可以利用它来把元组里的信息友好地呈现出来
9 print(delhi._asdict())

以上代码执行的结果为:

('name', 'country', 'population', 'coordinates')
OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935), ('coordinates', LatLong(lat=28.613889, long=77.208889))])
name: Delhi NCR
country: IN
population: 21.935
coordinates: LatLong(lat=28.613889, long=77.208889)

 

切片

  在
Python
里,像列表(list)、元组(tuple)和字符串(str)那类连串类型都支持切片操作,可是事实上切片操作比人们所想象的要强大很多。

为啥切片和距离会忽略最终一个成分

  在切除和距离操作里不含有区间范围的末段3个要素是
Python 的作风,那些习惯符合 Python、C 和其他语言里以 0
作为开首下标的守旧。那样做带来的补益如下:

  1. 当唯有最后1个职责信息时,大家也能够便捷看出切片和距离里有几个要素:range(3)
    和 my_list[:3] 都返回 3 个元素

  2. 当起止地方消息都可知时,大家得以高速计算出切片和距离的尺寸,用后多少个数减去第二个下标(stop –
    start)即可

  3. 如此做也让我们得以选用随机三个下标来把系列分割成不重叠的两有的,只要写成
    my_list[:x] 和 my_list[x:] 就足以了,如下所示

    1 l = [10, 20 , 30 ,40, 50, 60]
    2
    3 #取l列表中切五个因素
    4 print(‘l列表中的前多个要素:’, l[:2])
    5
    6 #从第一个目录开首取值
    7 print(‘l列表从第一个目录先导现在取值:’,l[2:])

以上代码直接的结果为:

l列表中的前两个元素: [10, 20]
l列表从第二个索引开始往后取值: [30, 40, 50, 60]

对目的举行切开

  三个斐然的绝密是,我们还足以用
s[a:b:c] 的花样对 s 在 a 和 b之间以 c 为距离取值。c
的值还足以为负,负值意味着反向取值。上边包车型客车 3 个例子更直观些:

1 s = 'bicycle'
2 
3 print('s隔三个取值:', s[::3])
4 
5 print('s反向输出:', s[::-1])
6 
7 print('s反向输出,隔两个取值:', s[::-2])

上述代码直接的结果为:

s隔三个取值: bye
s反向输出: elcycib
s反向输出,隔两个取值: eccb

  a:b:c
那种用法只美观做目录或然下标用在 [] 中来回到二个切开对象:slice(a, b,
c)。在 10.4.1 节中会讲到,对seq[start:stop:step]
进行求值的时候,Python 会调用seq.__getitem__(slice(start, stop,
step))。即便你还不会自定义种类类型,精通一下切开对象也是有实益的。例如你能够给切片命名,就如电子表格软件里给单元格区域取名字一样。

举个
 纯文本文件格局的收据以一行字符串的样式被解析

 1 invoice = """
 2     0.....6................................40........52...55........
 3     1909  Pimoroni PiBrella                $17.50    3    $52.50
 4     1489  6mm Tactile Switch x20           $4.95     2    $9.90
 5     1510  Panavise Jr. - PV-201            $28.00    1    $28.00
 6     1601  PiTFT Mini Kit 320x240           $34.95    1    $34.95
 7 """
 8 
 9 SKU = slice(0, 10)
10 DESCRIPTION = slice(10, 40)
11 UNIT_PRICE = slice(40, 52)
12 QUANTITY = slice(52, 55)
13 ITEM_TOTAL = slice(55, None)
14 line_items = invoice.split('\n')[2:]
15 
16 for item in line_items:
17     print(item[UNIT_PRICE], item[DESCRIPTION])

上述代码直接的结果为:

   $17.50    Pimoroni PiBrella             
   $4.95     6mm Tactile Switch x20        
   $28.00    Panavise Jr. - PV-201         
   $34.95    PiTFT Mini Kit 320x240        

给切片赋值

举个🌰 

 1 l = list(range(10))
 2 print('l列表的原有元素:', l)
 3 
 4 #利用切片赋值
 5 l[2:5] = [20, 30]
 6 print('利用l[2:5]以后的结果:', l)
 7 
 8 #删除列表中指定索引范围的值
 9 del l[5:7]
10 print('删除l列表第5-7个索引值以后的l列表:', l)
11 
12 #从第三个索引开始,间隔两个索引赋值
13 l[3::2] = [11, 22]
14 print('l列表从第三个索引开始,隔两个元素赋值以后的l列表:', l)

以上代码直接的结果为:

l列表的原有元素: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
利用l[2:5]以后的结果: [0, 1, 20, 30, 5, 6, 7, 8, 9]
删除l列表第5-7个索引值以后的l列表: [0, 1, 20, 30, 5, 8, 9]
l列表从第三个索引开始,隔两个元素赋值以后的l列表: [0, 1, 20, 11, 5, 22, 9]

注意:

  如若赋值的指标是一个切开,那么赋值语句的右侧必须是个可迭代对象。即使唯有单独二个值,也要把它转换到可迭代的行列。

 

队列的增量赋值 

  增量赋值运算符
+= 和 *=
的显现取决于它们的首个操作对象。简单起见,大家把探讨集中在增量加法(+=)上,但是那一个概念对
*= 和别的增量运算符来说都以一律的。

  +=
背后的与众差别方式是 __iadd__
(用于“就地加法”)。然则只要叁个类没有兑现那一个法子的话,Python
会退一步调用 __add__ 。考虑上面这几个大概的表明式:

a += b

  如果 a
实现了 __iadd__ 方法,就会调用那一个措施。同时对可变体系(例如
list、bytearray 和 array.array)来说,a 会就地转移,就如调用了
a.extend(b) 一样。不过一旦 a 没有落到实处 __iadd__ 的话,a+= b
那几个表达式的意义就变得跟 a = a + b 一样了:首先计算 a
+b,得到3个新的对象,然后赋值给
a。也正是说,在那个表明式中,变量名会不会被波及到新的目的,完全取决于那个种类有没有落到实处__iadd__
那个主意。

举个
体现的是 *= 在可变和不足变连串上的作用:

>>> l = [1, 2, 3]
>>> id(l)
4316848904
>>> l *= 3
>>> l
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> id(l)
4316848904
>>> t = (1, 2, 3)
>>> id(t)
4316864656
>>> t *= 2
>>> t
(1, 2, 3, 1, 2, 3)
>>> id(t)
4316467112

  对不可变系列实行双重拼接操作的话,效能会非常的低,因为每趟都有一新对象,而解释器要求把原来对象中的成分先复制到新的靶子里,然后再扩展新的因素。

  

list.sort方法和停放函数sorted

   list.sort
方法会就地排连串表,也正是说不会把原列表复制一份。那也是以此措施的重回值是
None 的案由,提示你本办法不会新建三个列表。在那种景色下回到 None 其实是
Python
的一个规矩:假若1个函数也许措施对目的开始展览的是就地转移,那它就应有回到
None,好让调用者知道传入的参数产生了改观,而且没有发生新的对象。例如,random.shuffle
函数也遵从了这么些规矩。

  与
list.sort 相反的是放到函数 sorted,它会新建二个列表作为重临值。那一个艺术还行别的情势的可迭代对象作为参数,甚至席卷不得变连串或生成器。而不论
sorted 接受的是怎么样的参数,它说到底都会回来多少个列表。

  不管是
list.sort 方法依旧 sorted 函数,都有八个可选的严重性字参数。

reverse

  假诺被设定为
True,被排序的系列里的成分会以降序输出(约等于说把最大值当作最小值来排序)。那么些参数的暗许值是
False。

key

  一个唯有3个参数的函数,那个函数会被用在体系里的每八个成分上,所暴发的结果将是排序算法依赖的自己检查自纠关键字。比如说,在对一些字符串排序时,能够用
key=str.lower 来兑现忽略大小写的排序,大概是用 key=len
进行基于字符串长度的排序。那个参数的私下认可值是恒等函数(identity
function),也等于暗中认可用成分协调的值来排序。

举个🌰

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

 

用bisect来管理已排序的系列

  bisect
模块蕴含多个举足轻重函数,bisect 和
insort,三个函数都使用二分查找算法来在稳步系列中检索或插队成分。

用bisect来搜索

  bisect(haystack,
needle) 在
haystack(干草垛)里摸索needle(针)的地点,该地方满意的口径是,把
needle 插入那几个岗位然后,haystack
还是能保证升序。也便是在说这一个函数重回的职位前边的值,都低于或等于 needle
的值。在那之中 haystack 必须是一个萧规曹随的类别。你能够先用 bisect(haystack,
needle) 查找地点 index,再用 haystack.insert(index, needle)
来插入新值。但你也可用insort 来一步到位,并且后者的进度更快一些。

举个 在静止序列中用
bisect 查找有个别成分的插入地方

 1 import bisect
 2 import sys
 3 
 4 HAYSTACK = [1, 4, 5, 6, 8, 12, 15, 20, 21, 23, 23, 26, 29, 30]
 5 NEEDLES = [0, 1, 2, 5, 8, 10, 22, 23, 29, 30, 31]
 6 
 7 ROW_FMT = '{0:2d} @ {1:2d}    {2}{0:<2d}'  #格式化输出:左边的是占位符的位置0 1 2... :右边的是对齐宽度
 8 
 9 
10 def demo(bisect_fn):
11     for needle in reversed(NEEDLES):
12         position = bisect_fn(HAYSTACK, needle)
13         offset = position * '  |'
14         print(ROW_FMT.format(needle, position, offset))
15 
16 if __name__ == "__main__":
17 
18     if sys.argv[-1] == 'left':
19         bisect_fn = bisect.bisect_left
20     else:
21         bisect_fn = bisect.bisect
22 
23     print('DEMO:', bisect_fn.__name__)
24     print('haystack ->', ' '.join('%2d' % n for n in HAYSTACK))
25     demo(bisect_fn)

上述代码直接的结果为:

DEMO: bisect
haystack ->  1  4  5  6  8 12 15 20 21 23 23 26 29 30
31 @ 14      |  |  |  |  |  |  |  |  |  |  |  |  |  |31
30 @ 14      |  |  |  |  |  |  |  |  |  |  |  |  |  |30
29 @ 13      |  |  |  |  |  |  |  |  |  |  |  |  |29
23 @ 11      |  |  |  |  |  |  |  |  |  |  |23
22 @  9      |  |  |  |  |  |  |  |  |22
10 @  5      |  |  |  |  |10
 8 @  5      |  |  |  |  |8 
 5 @  3      |  |  |5 
 2 @  1      |2 
 1 @  1      |1 
 0 @  0    0 

遵照一个分数,找到它所对应的战绩

 1 import bisect
 2 
 3 
 4 def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
 5     i = bisect.bisect(breakpoints, score)   #获取breakpoints的索引位置
 6     print('{}在{}中的索引位置:{}, 英文的分数为:{}'.format(score, breakpoints, i, grades[i]))
 7     return grades[i]        #返回对应的英文成绩
 8 
 9 grade(80)
10 grade(33)
11 
12 [grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]

上述代码直接的结果为:

80在[60, 70, 80, 90]中的索引位置:3, 英文的分数为:B
33在[60, 70, 80, 90]中的索引位置:0, 英文的分数为:F
33在[60, 70, 80, 90]中的索引位置:0, 英文的分数为:F
99在[60, 70, 80, 90]中的索引位置:4, 英文的分数为:A
77在[60, 70, 80, 90]中的索引位置:2, 英文的分数为:C
70在[60, 70, 80, 90]中的索引位置:2, 英文的分数为:C
89在[60, 70, 80, 90]中的索引位置:3, 英文的分数为:B
90在[60, 70, 80, 90]中的索引位置:4, 英文的分数为:A
100在[60, 70, 80, 90]中的索引位置:4, 英文的分数为:A

 

用bisect.insort插入新因素

  排序很耗费时间,由此在获得三个静止体系之后,咱们最棒能够保证它的雷打不动。bisect.insort
就是为了那一个而留存的。

  insort(seq,
item) 把变量 item 插入到行列 seq 中,并能保持
seq的升序顺序,如下:

 1 import bisect
 2 import random
 3 
 4 SIZE = 7
 5 
 6 random.seed(1729)
 7 
 8 my_list = []
 9 for i in range(SIZE):
10     new_item = random.randrange(SIZE*2)
11     bisect.insort(my_list, new_item)
12     print('%2d ->' % new_item, my_list)

上述代码间接的结果为:

10 -> [10]
 0 -> [0, 10]
 6 -> [0, 6, 10]
 8 -> [0, 6, 8, 10]
 7 -> [0, 6, 7, 8, 10]
 2 -> [0, 2, 6, 7, 8, 10]
10 -> [0, 2, 6, 7, 8, 10, 10]

 

当列表不是首要选取时

  固然列表既灵活又简便,但面对各类急需时,大家大概会有更好的采取。比如,要存放
1000万个浮点数的话,数组(array)的频率要高得多,因为数组在背后存的并不是
float 对象,而是数字的机械翻译,也正是字节表述。这点就跟 C
语言中的数组一样。再比如说,假设急需反复对队列做先进先出的操作,deque(双端队列)的进程相应会更快。

数组

  固然大家供给1个只包涵数字的列表,那么
array.array 比 list 更便捷。数组协理具有跟可变体系有关的操作,包蕴.pop、.insert
和.extend。其余,数组还提供从文件读取和存入文件的更快的措施,如.frombytes
和 .tofile。

举个 四个浮点型数组的创导、存入文件和从文件读取的历程

 1 from array import array
 2 from random import random
 3 
 4 
 5 #利用一个可迭代对象来建立一个双精度浮点数组(类型码是 'd'),这里我们用的可迭代对象是一个生成器表达式
 6 floats = array('d', (random() for i in range(10**7)))
 7 print(floats[-1])
 8 
 9 #把数组存入一个二进制文件里
10 with open('floats.bin', 'wb') as fb:
11     floats.tofile(fb)
12 
13 
14 floats2 = array('d')
15 
16 #把 1000 万个浮点数从二进制文件里读取出来
17 with open('floats.bin', 'rb') as fb:
18     floats2.fromfile(fb, 10 ** 7)
19 
20 print(floats2[-1])
21 
22 #检查两个数组的内容是不是完全一样
23 if floats == floats2:
24     print('Yes')
25 else:
26     print('NO')

如上代码执行的结果为:

0.25921054635939245
0.25921054635939245
Yes

   从上边的代码大家能得出结论,array.tofile
和 array.fromfile
用起来很简单。把那段代码跑一跑,你还会发现它的快慢也很快。1个小规模试制验告诉本人,用
array.fromfile 从1个二进制文件里读出 一千 万个双精度浮点数只供给 0.1
秒,那比从文本文件里读取的进度要快 60倍,因为后者会选拔内置的 float
方法把每一行文字转换来浮点数。

  此外,使用
array.tofile
写入到二进制文件,比以每行3个浮点数的主意把富有数字写入到文本文件要快 7
倍。此外,一千 万个如此的数在二进制文件里只占用 80 000 000
个字节(每种浮点数占用 8个字节,不需求其它额外空间),假若是文本文件的话,我们须求 181 515
7叁十多个字节。

内部存款和储蓄器视图 

  memoryview
是八个内置类,它能让用户在不复制内容的意况下操作同二个数组的不一致切片。

  memoryview.cast
的概念跟数组模块类似,能用不相同的主意读写同一块内存数据,而且内容字节不会轻易活动。那听上去又跟
C 语言中类型转换的定义差不离。memoryview.cast
会把同一块内部存款和储蓄器里的始末打包成三个全新的
memoryview 对象给你。

举个
通过改变数组中的一个字节来更新数组里有些成分的值

 1 import array
 2 
 3 #利用含有 5 个短整型有符号整数的数组(类型码是 'h')创建一个memoryview
 4 numbers = array.array('h', [-2, -1, 0, 1, 2])
 5 
 6 memv = memoryview(numbers)
 7 print('memv[0]:', memv[0])
 8 
 9 #创建一个 memv_oct,这一次是把 memv 里的内容转换成 'B' 类型,也就是无符号字符
10 memv_oct = memv.cast('B')
11 
12 #转换成list
13 print('memv to list:', memv_oct.tolist())
14 
15 print('memv_oct[5]:', memv_oct[5])
16 
17 #修改memv_oct第五个索引的值为4
18 memv_oct[5] = 4
19 
20 print('numbers:', numbers)

如上代码执行的结果为:

memv[0]: -2
memv to list: [254, 255, 255, 255, 0, 0, 1, 0, 2, 0]
memv_oct[5]: 0
numbers: array('h', [-2, -1, 1024, 1, 2])

NumPy和SciPy

  凭借着
NumPy 和 SciPy 提供的高阶数组和矩阵操作,Python
成为科学总结应用的主流语言。NumPy 达成了多维同质数组(homogeneous
array)和矩阵,那几个数据结构不但能处理数字,还是能存放别的由用户定义的笔录。通过
NumPy,用户能对这么些数据结构里的要素实行高效的操作。

举个 对
numpy.ndarray 的行和列举办基本操作

 1 import numpy
 2 
 3 #创建一个一维数组,取值为0~11
 4 a = numpy.arange(12)
 5 print(a)
 6 print('-'*40)
 7 
 8 #数组的维度
 9 print(a.shape)
10 print('-'*40)
11 
12 #转换数组的维度为3行四列
13 a.shape = 3, 4
14 print('转换数组维度以后的取值:\n', a)
15 print('-'*40)
16 
17 print('打印第2个索引的数据:', a[2])
18 print('-'*40)
19 
20 print('打印第2个索引中第1个索引的值:', a[2][1])
21 print('-'*40)
22 
23 print('打印第一列中的数据:', a[:, 1])
24 print('-'*40)
25 
26 #把行和列交过,得到一个新的数组
27 print('行和列交互以后的数组:\n', a.transpose())
28 print('-'*40)

如上代码执行的结果为:

[ 0  1  2  3  4  5  6  7  8  9 10 11]
----------------------------------------
(12,)
----------------------------------------
转换数组维度以后的取值:
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
----------------------------------------
打印第2个索引的数据: [ 8  9 10 11]
----------------------------------------
打印第2个索引中第1个索引的值: 9
----------------------------------------
打印第一列中的数据: [1 5 9]
----------------------------------------
行和列交互以后的数组:
 [[ 0  4  8]
 [ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]]
----------------------------------------

NumPy
也得以对 numpy.ndarray 中的成分举办抽象的读取、保存和此外操作:

 1 import numpy
 2 
 3 #使用numpy创建一个数组
 4 floats = numpy.array([ 3016362.69195522, 535281.10514262, 4566560.44373946])
 5 print(floats)
 6 
 7 #对数组中的每个元素修改
 8 floats *= .5
 9 print(floats)
10 
11 #把修改后的数组存储到文件中
12 numpy.save('floats-10M', floats)
13 
14 #读取保存文件的内容
15 floats2 = numpy.load('floats-10M.npy', 'r+')
16 print('floats-10M:', floats2)
17 
18 #修改读取文件中的数据
19 floats2 *= 6
20 print('打印读取数据乘以6以后的结果:', floats2)
21 
22 #通过索引取值
23 print('取floats2中数组第2个索引的值:', floats2[2:])
24 
25 #倒序输出结果
26 print('倒序输出floats2的结果:', floats2[::-1])

如上代码执行的结果为:

[ 3016362.69195522   535281.10514262  4566560.44373946]
[ 1508181.34597761   267640.55257131  2283280.22186973]
floats-10M: [ 1508181.34597761   267640.55257131  2283280.22186973]
打印读取数据乘以6以后的结果: [  9049088.07586566   1605843.31542786  13699681.33121838]
取floats2中数组第2个索引的值: [ 13699681.33121838]
倒序输出floats2的结果: [ 13699681.33121838   1605843.31542786   9049088.07586566]

双向队列和其它花样的队列

  collections.deque
类(双向队列)是贰个线程安全、能够长足从互相添加也许去除成分的数据类型。而且只要想要有一种数据类型来存放在“近来选择的多少个因素”,deque
也是二个很好的精选。那是因为在新建3个双向队列的时候,你能够钦赐那几个行列的深浅,借使那几个队列满员了,还足以从反向端删除过期的成分,然后在尾端添加新的成分。

举个
 使用双向队列

 1 from collections import deque
 2 
 3 
 4 #创建一个双向队列,队列最大长度为10
 5 dq = deque(range(10), maxlen=10)
 6 print('初始化的双向队列:', dq)
 7 
 8 #旋转队列
 9 '''
10 队列的旋转操作接受一个参数 n,当 n > 0 时,队列的最右边的 n
11 个元素会被移动到队列的左边。当 n < 0 时,最左边的 n 个元素会被
12 移动到右边
13 '''
14 dq.rotate(3)
15 print('旋转队列以后:', dq)
16 
17 dq.rotate(-4)
18 print('旋转队列以后:', dq)
19 
20 #当往一个已满的队列中添加数据,会把开头的数据替换掉
21 dq.appendleft('20')
22 print('往队列中放入数据:', dq)
23 
24 #往队列中扩展一个列表,前面的内容会被自动删除掉
25 dq.extend([20, 30 , 40])
26 print('扩展以后的队列:', dq)
27 
28 #从最队列的最前面扩展,后面的内容会被自动删除叼
29 dq.extendleft([100, 200, 300])
30 print('列队最前面扩展以后的结果:', dq)

上述代码执行的结果为:

初始化的双向队列: deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
旋转队列以后: deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
旋转队列以后: deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
往队列中放入数据: deque(['20', 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
扩展以后的队列: deque([3, 4, 5, 6, 7, 8, 9, 20, 30, 40], maxlen=10)
列队最前面扩展以后的结果: deque([300, 200, 100, 3, 4, 5, 6, 7, 8, 9], maxlen=10)

 

 

队列类型分类

 

   所谓连串,即成分有序排列,python标准库用C实现了拉长的行列类型,遵照种类中是还是不是可存放分裂门类的多少分为”容器种类”和”扁平连串”。

  容器体系能够存放统统类型的数码,而扁平系列只可以存放一种档次
     

    容器序列:list、tuple、collections.deque   
    扁平序列:str、bytes、bytearray、memoryview、array.array
  
  按照是否能修改的标准序列又可分为"可变序列"和"不可变序列":      
    可变序列:list、bytearrary、array.arrary、collections.deque和memoryview   
    不可变序列:tuple、str和bytes

  由于可变序列继承自不可变序列,所以可变序列继承的方法也较多,下面看看它们包含的方法:   
方法名 不可变序列 可变序列
__contains__  有 有 
__iter__  有  有 
 __len__  有  有 
__getitem__   有  有 
__reversed__   有  有 
index   有  有 
count   有  有 
__setitem__    有 
__delitem__   有 
insert   有 
append   有 
reverse   有 
extend   有 
pop   有 
remove   有 
__iadd__    有 

  

  大家以tuple和list类型为例,比较源代码中的方法,可以显明发现list的方法多于tuple:

  

威尼斯人线上娱乐 2

 

本文首要内容

  体系类型分类:

    (1)容器类别、扁平系列

    (2)可变系列、不可变系列

  列表推导式

  生成器表明式

  元组拆包

  切片

  排序(list.sort方法和sorted函数)

  bisect

 

  文中代码均位居github上:

 

容器系列

容器连串能够存放差异品种的多寡,像list、tuple和collections.deque。

列表推导式

# 列表推导式生成的是列表,会占用系统内存
# 基本语法

list_1 = [x for x in range(1, 20)]
list_2 = [x ** 2 for x in range(1, 20)]


print(list_1)  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
print(list_2)  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361]

# 笛卡尔积型的列表推导式
list_3 = [(x, y) for x in range(1, 3)        # 1,2
                 for y in range(7, 10)]      # 7、8、9

                                             # 该表达式会先将1分别和7、8、9组合,然后再拿2和7、8、9组合,共6对
print(list_3)  # [(1, 7), (1, 8), (1, 9), (2, 7), (2, 8), (2, 9)]


list_4 = [x+y for x in range(1, 3)
                 for y in range(7, 10)]

print(list_4)   # [8, 9, 10, 9, 10, 11]

# 还可以添加if语句
l = [1, 3, 4, 33, 45, 36, 422, 34, 67, 23, -4, -7, -345, 46, -6, -45, 32, -8, -4, 67, -4]

list_5 = [x for x in l if x > 0]   # 只取出大于0的生成列表
print(list_5)                      # [1, 3, 4, 33, 45, 36, 422, 34, 67, 23, 46, 32, 67]

 

队列类型分类

 

   所谓系列,即成分有序排列,python标准库用C完成了足够的连串类型,依照体系中是或不是可存放分化连串的数量分为”容器类别”和”扁平种类”。

  容器体系能够存放统统类型的多寡,而扁平连串只可以存放一系列型      

    容器序列:list、tuple、collections.deque   
    扁平序列:str、bytes、bytearray、memoryview、array.array
  
  按照是否能修改的标准序列又可分为"可变序列"和"不可变序列":      
    可变序列:list、bytearrary、array.arrary、collections.deque和memoryview   
    不可变序列:tuple、str和bytes

  由于可变序列继承自不可变序列,所以可变序列继承的方法也较多,下面看看它们包含的方法:   
方法名 不可变序列 可变序列
__contains__  有 有 
__iter__  有  有 
 __len__  有  有 
__getitem__   有  有 
__reversed__   有  有 
index   有  有 
count   有  有 
__setitem__    有 
__delitem__   有 
insert   有 
append   有 
reverse   有 
extend   有 
pop   有 
remove   有 
__iadd__    有 

  

  大家以tuple和list类型为例,相比较源代码中的方法,能够明显发现list的章程多于tuple:

  

 

扁平体系

扁平类别只可以存在一连串型的数码,像str、bytes、bytearray、memoryview、array.array。

留神:容器类别存放是专擅档次的对象的引用,而扁平序列存在是值而不是引用,是一段连接的内部存款和储蓄器空间。

依据是不是能被改动来差距:

生成器表明式

# 虽然列表推导式可以用来初始化元组、数组或其他序列类型,但是列表推导式会直接生成列表,占用内存
# 而生成器遵守了迭代器协议,可以逐个产出元素,而不是先建立一个完整的列表


# 生成器表达式直接将推导式的方括号换成圆括号即可

g = (x for x in range(1, 10000))

print(g)    # <generator object <genexpr> at 0x105c0efc0> :生成器对象


from collections import Iterable, Iterator

if isinstance(g, Iterable):
    print("iterable")          # 输出iterable: 说明生成器g是可迭代的

if isinstance(g, Iterator):
    print("iterator")          # 输出iterator:说明生成器g是迭代器

 

  下边大家来对待一下列表推导式和生成器的频率

# 比较列表推导式和生成器
import time

start_time = time.time()
l = [x for x in range(1000000)]
print(time.time() - start_time)     # 0.1361069679260254

start_time = time.time()
g = (x for x in range(1000000))
print(time.time() - start_time)     # 1.1205673217773438e-05

# 可见,生成器远快于推导式

 

列表推导式

# 列表推导式生成的是列表,会占用系统内存
# 基本语法

list_1 = [x for x in range(1, 20)]
list_2 = [x ** 2 for x in range(1, 20)]


print(list_1)  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
print(list_2)  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361]

# 笛卡尔积型的列表推导式
list_3 = [(x, y) for x in range(1, 3)        # 1,2
                 for y in range(7, 10)]      # 7、8、9

                                             # 该表达式会先将1分别和7、8、9组合,然后再拿2和7、8、9组合,共6对
print(list_3)  # [(1, 7), (1, 8), (1, 9), (2, 7), (2, 8), (2, 9)]


list_4 = [x+y for x in range(1, 3)
                 for y in range(7, 10)]

print(list_4)   # [8, 9, 10, 9, 10, 11]

# 还可以添加if语句
l = [1, 3, 4, 33, 45, 36, 422, 34, 67, 23, -4, -7, -345, 46, -6, -45, 32, -8, -4, 67, -4]

list_5 = [x for x in l if x > 0]   # 只取出大于0的生成列表
print(list_5)                      # [1, 3, 4, 33, 45, 36, 422, 34, 67, 23, 46, 32, 67]

 

可变种类

list、bytearray、array.array、collections.deque 和
memoryview

元组拆包

# 我们经常这样给两个变量同时赋值
a, b = 1, 2
print(a, b)     # 1 2

# 还可以这样
a, b = [1, 2]
print(a, b)     # 1 2

# 也可以这样
a, b = (1, 2)
print(a, b)     # 1 2

# 甚至可以这样
a, b = "ab"
print(a, b)     # a b

'''
    像以上这样连续的赋值方式,右边可以使用逗号隔开;也可以是序列。

    当拆包赋值的是序列时,python解释器会先找该序列中的__iter__方法,如果该方法不存在,则寻找__getitem__方法。

    接下来说其他用法
'''

# 赋值后优雅地交换两个变量
a, b = (1, 2)
a, b = b, a
print(a, b)        # 2 1

# 使用*号来处理多余的数据
a, b, *s = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(a, b, s)        # 1 2 [3, 4, 5, 6, 7, 8, 9]
                      # 这样从第三个元素开始的所有值都赋给了s

a, b, *s = (1, 2, 3, 4, 5, 6, 7, 8, 9)
print(a, b, s)        # 1 2 [3, 4, 5, 6, 7, 8, 9]
                      # 注意,本来是元组,赋之后的s变成了列表. 如果s为空的话也会返回空列表

*s, a, b = (1, 2, 3, 4, 5, 6, 7, 8, 9)
print(s, a, b)        # [1, 2, 3, 4, 5, 6, 7] 8 9
                      # *s也可以放在前面

a, *s, b = (1, 2, 3, 4, 5, 6, 7, 8, 9)
print(a, s, b)        # 1 [2, 3, 4, 5, 6, 7, 8] 9
                      # *s也可以放在中间

# 嵌套元组拆包
a, b, (c, d) = (1, 2, (3, 4))
print(a, b, c, d)     # 1 2 3 4
                      # 只要按照右边的形式就可赋值

a, b, *c = (1, 2, (3, 4))
print(a, b, c)     # 1 2 [(3, 4)]

 

威尼斯人线上娱乐 3威尼斯人线上娱乐 4

 1 ################################
 2 #
 3 # 以下的例子用以说明拆包赋值时,解释器会按照__iter__、__getitem__的顺序调用类中的方法
 4 #
 5 ################################
 6 class Foo:
 7     def __init__(self, s):
 8         self.s = s
 9 
10     def __iter__(self):
11         print("iter")
12         return iter(self.s)
13 
14     def __getitem__(self, item):
15         return self.s[item]
16 
17 if __name__ == "__main__":
18     foo = Foo("sdfafasfasf")
19     a, b, *s = foo
20     print(a, b)

拆包赋值的当中贯彻

 

  在此以前大家由此源码已经相比较过list和tuple类中的方法和天性,上边列出《流畅的python》整理的列表和元组的点子及质量:

表 列表或元组的措施和个性

  列  表 元  组
s.__add__(s2)
· ·
s.__iadd__(s2) ·  
s.append(e) ·  
s.clear() ·  
s.__contains__(e) · ·
s.copy() ·  
s.count(e) · ·
s.__delitem__(p) ·  
s.extend(it) ·  
s.__getitem__(p) · ·
s.__getnewargs__()   ·
s.index(e) · ·
x.insert(p,e) ·  
s.__iter__() · ·
s.__len__() · ·
s.__mul__(n) · ·
s.__imul__(n) ·  
s.__rmul__(n) · ·
s.pop([p]) ·  
s.remove(e) ·  
s.reverse() ·  
s.__reversed__() ·  
s.__setitem__(p,e) ·  
s.sort([key], [reverse]) ·  

   

  表明:以元宵节组中不加黑点的不表示一定不能够如此使用,只是其功效和列表分化(表明里面有表明)。例如五个元组a和b进行增量赋值a+=b也是足以的,只是这么些操作不是就地拼接,而是生成了新的元组。

生成器表明式

# 虽然列表推导式可以用来初始化元组、数组或其他序列类型,但是列表推导式会直接生成列表,占用内存
# 而生成器遵守了迭代器协议,可以逐个产出元素,而不是先建立一个完整的列表


# 生成器表达式直接将推导式的方括号换成圆括号即可

g = (x for x in range(1, 10000))

print(g)    # <generator object <genexpr> at 0x105c0efc0> :生成器对象


from collections import Iterable, Iterator

if isinstance(g, Iterable):
    print("iterable")          # 输出iterable: 说明生成器g是可迭代的

if isinstance(g, Iterator):
    print("iterator")          # 输出iterator:说明生成器g是迭代器

 

  上边大家来相比一下列表推导式和生成器的效能

# 比较列表推导式和生成器
import time

start_time = time.time()
l = [x for x in range(1000000)]
print(time.time() - start_time)     # 0.1361069679260254

start_time = time.time()
g = (x for x in range(1000000))
print(time.time() - start_time)     # 1.1205673217773438e-05

# 可见,生成器远快于推导式

 

不行变系列

tuple、str 和 bytes

切片

'''
    在python中,内置的序列类型都支持切片操作,切片操作的用法十分简单:
    list[start: stop: step]    , 其中不包括区间范围内最后一个(事实上这是python的风格,一般不包含区间最后一个)
    python里面能使用切片操作是因为实现了__getitem__方法,切片时会给该方法传递slice(start: stop: step) 参数
'''

if __name__ == "__main__":
    # 基本操作
    l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    print(l[2:])     # 第3个元素到最后   :[3, 4, 5, 6, 7, 8, 9]
    print(l[:3])     # 第一个元素到最后   :[1, 2, 3]

    s = "abcdefghijklmn"
    print(s[2::2])   # 从第三个字母开始,隔一个字母取一个 : cegikm
    print(s[::-1])   # 倒序排列 : nmlkjihgfedcba
    print(s[::-2])   # 倒序隔一个取一个 nljhfdb
    print(s[-2::-2]) # 倒序第二隔开始,隔一个取一个

    # 利用切片赋值
    l[2:5] = [20, 30]
    print(l)         # [1, 2, 20, 30, 6, 7, 8, 9]
    try:
        l[2:5] = 40      # 报错:TypeError: can only assign an iterable
                         # 利用切片赋值时传入的必须是可迭代对象
    except Exception as e:
        print(e)         # can only assign an iterable
    l[2:5] = (40,)
    print(l)             # [1, 2, 40, 7, 8, 9]
    l[2:3] = "sajfljls"  # 字符串属于序列,也可以迭代
    print(l)             # [1, 2, 's', 'a', 'j', 'f', 'l', 'j', 'l', 's', 7, 8, 9]

 

元组拆包

# 我们经常这样给两个变量同时赋值
a, b = 1, 2
print(a, b)     # 1 2

# 还可以这样
a, b = [1, 2]
print(a, b)     # 1 2

# 也可以这样
a, b = (1, 2)
print(a, b)     # 1 2

# 甚至可以这样
a, b = "ab"
print(a, b)     # a b

'''
    像以上这样连续的赋值方式,右边可以使用逗号隔开;也可以是序列。

    当拆包赋值的是序列时,python解释器会先找该序列中的__iter__方法,如果该方法不存在,则寻找__getitem__方法。

    接下来说其他用法
'''

# 赋值后优雅地交换两个变量
a, b = (1, 2)
a, b = b, a
print(a, b)        # 2 1

# 使用*号来处理多余的数据
a, b, *s = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(a, b, s)        # 1 2 [3, 4, 5, 6, 7, 8, 9]
                      # 这样从第三个元素开始的所有值都赋给了s

a, b, *s = (1, 2, 3, 4, 5, 6, 7, 8, 9)
print(a, b, s)        # 1 2 [3, 4, 5, 6, 7, 8, 9]
                      # 注意,本来是元组,赋之后的s变成了列表. 如果s为空的话也会返回空列表

*s, a, b = (1, 2, 3, 4, 5, 6, 7, 8, 9)
print(s, a, b)        # [1, 2, 3, 4, 5, 6, 7] 8 9
                      # *s也可以放在前面

a, *s, b = (1, 2, 3, 4, 5, 6, 7, 8, 9)
print(a, s, b)        # 1 [2, 3, 4, 5, 6, 7, 8] 9
                      # *s也可以放在中间

# 嵌套元组拆包
a, b, (c, d) = (1, 2, (3, 4))
print(a, b, c, d)     # 1 2 3 4
                      # 只要按照右边的形式就可赋值

a, b, *c = (1, 2, (3, 4))
print(a, b, c)     # 1 2 [(3, 4)]

 

威尼斯人线上娱乐 5

 1 ################################
 2 #
 3 # 以下的例子用以说明拆包赋值时,解释器会按照__iter__、__getitem__的顺序调用类中的方法
 4 #
 5 ################################
 6 class Foo:
 7     def __init__(self, s):
 8         self.s = s
 9 
10     def __iter__(self):
11         print("iter")
12         return iter(self.s)
13 
14     def __getitem__(self, item):
15         return self.s[item]
16 
17 if __name__ == "__main__":
18     foo = Foo("sdfafasfasf")
19     a, b, *s = foo
20     print(a, b)

拆包赋值的中间贯彻

 

  此前大家经过源码已经相比较过list和tuple类中的方法和性质,上面列出《流畅的python》整理的列表和元组的方法及品质:

表 列表或元组的点子和特性

  列  表 元  组
s.__add__(s2) · ·
s.__iadd__(s2) ·  
s.append(e) ·  
s.clear() ·  
s.__contains__(e) · ·
s.copy() ·  
s.count(e) · ·
s.__delitem__(p) ·  
s.extend(it) ·  
s.__getitem__(p) · ·
s.__getnewargs__()   ·
s.index(e) · ·
x.insert(p,e) ·  
s.__iter__() · ·
s.__len__() · ·
s.__mul__(n) · ·
s.__imul__(n) ·  
s.__rmul__(n) · ·
s.pop([p]) ·  
s.remove(e) ·  
s.reverse() ·  
s.__reversed__() ·  
s.__setitem__(p,e) ·  
s.sort([key], [reverse]) ·  

   

  表明:以小端月组中不加黑点的不意味着一定不可能如此使用,只是其功能和列表不一样(表达里面有表明)。例如多少个元组a和b举办增量赋值a+=b也是能够的,只是那个操作不是就地拼接,而是生成了新的元组。

list——列表推倒

应用列表推导成立列表具有很好的可读性

比较上边两段代码

symbols = '$¢£¥€¤'
codes = []
for symbol in symbols:
    codes.append(ord(symbol))

codes
Out[5]:
[36, 162, 163, 165, 8364, 164]

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

选拔列表推导的代码显得非凡不难。列表推导仍是能够生成多重for循环的列表,如下代码所示:

a  = ['A','B','C','D']
b = [1,2,3,4]
c = [(i, j) for i in a for j in b]
c
Out[5]: 
[('A', 1),
 ('A', 2),
 ('A', 3),
 ('A', 4),
 ('B', 1),
 ('B', 2),
 ('B', 3),
 ('B', 4),
 ('C', 1),
 ('C', 2),
 ('C', 3),
 ('C', 4),
 ('D', 1),
 ('D', 2),
 ('D', 3),
 ('D', 4)]

d = [(i, j) for j in b for i in a]
d
Out[9]: 
[('A', 1),
 ('B', 1),
 ('C', 1),
 ('D', 1),
 ('A', 2),
 ('B', 2),
 ('C', 2),
 ('D', 2),
 ('A', 3),
 ('B', 3),
 ('C', 3),
 ('D', 3),
 ('A', 4),
 ('B', 4),
 ('C', 4),
 ('D', 4)]

用列表推导仍是能够代表filter和map,幸免使用难以通晓的lambda表明式,

symbols = '$¢£¥€¤'
beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))
beyond_ascii
Out[12]: 
[162, 163, 165, 8364, 164]
beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]
beyond_ascii
Out[14]: 
[162, 163, 165, 8364, 164]

排序(list.sort方法和sorted函数)

'''
    list.sort方法和sorted内置函数都有排序的功能,区别如下
        list.sort是就地排序列表,不会把原列表复制一份。该方法返回None,以提醒不会新建一个列表。
        sorted函数会新建一个列表作为返回值,这个函数可以接受任何可迭代对象,甚至包括不可变序列或生成器,最后返回的总是列表。

    list.sort和sorted都有两个参数:
        reverse:默认为False,设定为True以降序排列
        key:一个只有一个参数的函数,这个函数会作用于序列的每一个元素上,然后以该函数的结果作为关键字排序

'''

if __name__ == "__main__":
    # 1、list.sort就地排序,而sorted返回列表
    l = [x for x in range(10, 0, -1)]      # 初始化一个列表:[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    print(id(l), l)    # l最初的地址:4536449800 [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    l.sort()
    print(id(l), l)    # 排序后的地址:4536449800 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
                       # l前后的的地址没变,说明是就地排序


    l = [x for x in range(10, 0, -1)]  # 初始化一个列表:[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    print(id(l), l)  # l最初的地址:4415318984 [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    l = sorted(l)
    print(id(l), l)  # 排序后的地址:4415318792 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    # 2、sorted可以接受任何可迭代对象
    l = (x for x in range(10, 0, -1))
    print(type(l))        # 迭代器 <class 'generator'>
    print(sorted(l))      # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    s = "qwertyuiopasdfghjklzxcvbnm"   # 字符串序列
    print(sorted(s))      # ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

    s = (1, 3, 2, 456, 345, 12, 2, 5, 78, 34)   # 不可变元组
    print(sorted(s))      # [1, 2, 2, 3, 5, 12, 34, 78, 345, 456]

    # 3、reverse参数
    s = "qwertyuiopasdfghjklzxcvbnm"
    print(sorted(s, reverse=True))   # ['z', 'y', 'x', 'w', 'v', 'u', 't', 's', 'r', 'q', 'p', 'o', 'n', 'm', 'l', 'k', 'j', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']


    # 4、key参数
    s = "QwERTYuioPaSdfGHjKLzXcvbnm"
    print(sorted(s))    # ['E', 'G', 'H', 'K', 'L', 'P', 'Q', 'R', 'S', 'T', 'X', 'Y', 'a', 'b', 'c', 'd', 'f', 'i', 'j', 'm', 'n', 'o', 'u', 'v', 'w', 'z']
    print(sorted(s, key=str.lower))   # 忽略大小写 ['a', 'b', 'c', 'd', 'E', 'f', 'G', 'H', 'i', 'j', 'K', 'L', 'm', 'n', 'o', 'P', 'Q', 'R', 'S', 'T', 'u', 'v', 'w', 'X', 'Y', 'z']
    print(sorted(s, key=str.upper))   # 也是忽略大小写

##########################
#
#  以下自定义一个类也可使用sorted函数
#
##########################

class Obj:
    def __init__(self):
        self.s = [x for x in range(10, 0, -1)]

    def __getitem__(self, item):
        print("getitem")
        return self.s[item]

    def __repr__(self):
        return str(self.s)

    def __iter__(self):
        return iter(self.s)

obj = Obj()
print(obj)           # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

# 添加getitem后可以使用sorted函数  (实验时请注视掉getitem方法)
print(sorted(obj))   #  打印10次getitem   , [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 添加iter方法
print(sorted(obj))   # 此时解释器会先调用iter方法,不会再使用getitem方法
                     # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

使自定义类也可使用sorted函数调用

 

切片

'''
    在python中,内置的序列类型都支持切片操作,切片操作的用法十分简单:
    list[start: stop: step]    , 其中不包括区间范围内最后一个(事实上这是python的风格,一般不包含区间最后一个)
    python里面能使用切片操作是因为实现了__getitem__方法,切片时会给该方法传递slice(start: stop: step) 参数
'''

if __name__ == "__main__":
    # 基本操作
    l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    print(l[2:])     # 第3个元素到最后   :[3, 4, 5, 6, 7, 8, 9]
    print(l[:3])     # 第一个元素到最后   :[1, 2, 3]

    s = "abcdefghijklmn"
    print(s[2::2])   # 从第三个字母开始,隔一个字母取一个 : cegikm
    print(s[::-1])   # 倒序排列 : nmlkjihgfedcba
    print(s[::-2])   # 倒序隔一个取一个 nljhfdb
    print(s[-2::-2]) # 倒序第二隔开始,隔一个取一个

    # 利用切片赋值
    l[2:5] = [20, 30]
    print(l)         # [1, 2, 20, 30, 6, 7, 8, 9]
    try:
        l[2:5] = 40      # 报错:TypeError: can only assign an iterable
                         # 利用切片赋值时传入的必须是可迭代对象
    except Exception as e:
        print(e)         # can only assign an iterable
    l[2:5] = (40,)
    print(l)             # [1, 2, 40, 7, 8, 9]
    l[2:3] = "sajfljls"  # 字符串属于序列,也可以迭代
    print(l)             # [1, 2, 's', 'a', 'j', 'f', 'l', 'j', 'l', 's', 7, 8, 9]

 

元组

元组的意义不仅在于是不行变种类,更在乎它能够与记录关联起来,赋予它非凡的意义。

city, year, pop, chg, area = ('Tokyo', 2003, 32450, 0.66, 8014)
traveler_ids = [('USA', '31195855'), ('BRA', 'CE342567'), ('ESP', 'XDA205856')]
for passport in sorted(traveler_ids):
    print("%s,%s" % passport)

BRA,CE342567
ESP,XDA205856
USA,31195855

此地每种元组里的每一项都有了特定的意思。上边看看元组的拆包。

bisect

'''
    bisect模块主要用来管理有顺序的序列
    bisect模块包含的主要函数是bisect和insort,两个函数都使用二叉树方法搜索
    1、bisect(haystack, needle)
        haystack必须是一个有序的序列,该函数搜索needle在haystack中的位置,该位置使得将needle插入后haystack仍然升序
        查找到位置后可用haystack.insert()插入

    2、insort(seq, item)
        把item插入到seq中,并能保持seq的升序

'''

#  本人认为《流畅的python》中的对该模块介绍的例子比较经典,故引用之

# 1、关于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)


    '''   输出如下
    DEMO: bisect
    haystack ->  1  4  5  6  8 12 15 20 21 23 23 26 29 30
    31 @ 14      |  |  |  |  |  |  |  |  |  |  |  |  |  |31
    30 @ 14      |  |  |  |  |  |  |  |  |  |  |  |  |  |30
    29 @ 13      |  |  |  |  |  |  |  |  |  |  |  |  |29
    23 @ 11      |  |  |  |  |  |  |  |  |  |  |23
    22 @  9      |  |  |  |  |  |  |  |  |22
    10 @  5      |  |  |  |  |10
     8 @  5      |  |  |  |  |8 
     5 @  3      |  |  |5 
     2 @  1      |2 
     1 @  1      |1 
     0 @  0    0 
    '''
# 另,bisect.bisect函数有两个可选参数——lo和hi来缩小搜索范围,lo的默认值是0,hi的默认值是序列的长度
# 再另,bisect.bisect函数其实是bisect_right函数的别名,还有一个bisect_left,插入位置如果有相等的元素时,插入元素会放在它相等的
#      元素后面,后者会放在前面


# 根据分数,查到等级

def grade(score, breakpoints=[60, 70, 80, 90], grades = 'FDCBA'):
    i = bisect.bisect(breakpoints, score)     # 这里的bisect.bisect实际上使用的是bisect_right
    return grades[i]

print([grade(score) for score in [33, 55, 90, 87, 65, 78, 34, 60, 100]])

# 2、关于bisect.insort函数

import bisect
import random

SIZE = 7

random.seed(1729)

my_list = []
for i in range(SIZE):
    new_item = random.randrange(SIZE*2)
    bisect.insort(my_list, new_item)
    print('%2d ->' % new_item, my_list)

    '''输出:
    10 -> [10]
     0 -> [0, 10]
     6 -> [0, 6, 10]
     8 -> [0, 6, 8, 10]
     7 -> [0, 6, 7, 8, 10]
     2 -> [0, 2, 6, 7, 8, 10]
    10 -> [0, 2, 6, 7, 8, 10, 10]
    '''

# 另,insort函数也有insort_left,背后使用的是bisect_left

 

排序(list.sort方法和sorted函数)

'''
    list.sort方法和sorted内置函数都有排序的功能,区别如下
        list.sort是就地排序列表,不会把原列表复制一份。该方法返回None,以提醒不会新建一个列表。
        sorted函数会新建一个列表作为返回值,这个函数可以接受任何可迭代对象,甚至包括不可变序列或生成器,最后返回的总是列表。

    list.sort和sorted都有两个参数:
        reverse:默认为False,设定为True以降序排列
        key:一个只有一个参数的函数,这个函数会作用于序列的每一个元素上,然后以该函数的结果作为关键字排序

'''

if __name__ == "__main__":
    # 1、list.sort就地排序,而sorted返回列表
    l = [x for x in range(10, 0, -1)]      # 初始化一个列表:[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    print(id(l), l)    # l最初的地址:4536449800 [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    l.sort()
    print(id(l), l)    # 排序后的地址:4536449800 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
                       # l前后的的地址没变,说明是就地排序


    l = [x for x in range(10, 0, -1)]  # 初始化一个列表:[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    print(id(l), l)  # l最初的地址:4415318984 [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    l = sorted(l)
    print(id(l), l)  # 排序后的地址:4415318792 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    # 2、sorted可以接受任何可迭代对象
    l = (x for x in range(10, 0, -1))
    print(type(l))        # 迭代器 <class 'generator'>
    print(sorted(l))      # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    s = "qwertyuiopasdfghjklzxcvbnm"   # 字符串序列
    print(sorted(s))      # ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

    s = (1, 3, 2, 456, 345, 12, 2, 5, 78, 34)   # 不可变元组
    print(sorted(s))      # [1, 2, 2, 3, 5, 12, 34, 78, 345, 456]

    # 3、reverse参数
    s = "qwertyuiopasdfghjklzxcvbnm"
    print(sorted(s, reverse=True))   # ['z', 'y', 'x', 'w', 'v', 'u', 't', 's', 'r', 'q', 'p', 'o', 'n', 'm', 'l', 'k', 'j', 'i', 'h', 'g', 'f', 'e', 'd', 'c', 'b', 'a']


    # 4、key参数
    s = "QwERTYuioPaSdfGHjKLzXcvbnm"
    print(sorted(s))    # ['E', 'G', 'H', 'K', 'L', 'P', 'Q', 'R', 'S', 'T', 'X', 'Y', 'a', 'b', 'c', 'd', 'f', 'i', 'j', 'm', 'n', 'o', 'u', 'v', 'w', 'z']
    print(sorted(s, key=str.lower))   # 忽略大小写 ['a', 'b', 'c', 'd', 'E', 'f', 'G', 'H', 'i', 'j', 'K', 'L', 'm', 'n', 'o', 'P', 'Q', 'R', 'S', 'T', 'u', 'v', 'w', 'X', 'Y', 'z']
    print(sorted(s, key=str.upper))   # 也是忽略大小写

##########################
#
#  以下自定义一个类也可使用sorted函数
#
##########################

class Obj:
    def __init__(self):
        self.s = [x for x in range(10, 0, -1)]

    def __getitem__(self, item):
        print("getitem")
        return self.s[item]

    def __repr__(self):
        return str(self.s)

    def __iter__(self):
        return iter(self.s)

obj = Obj()
print(obj)           # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

# 添加getitem后可以使用sorted函数  (实验时请注视掉getitem方法)
print(sorted(obj))   #  打印10次getitem   , [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 添加iter方法
print(sorted(obj))   # 此时解释器会先调用iter方法,不会再使用getitem方法
                     # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

使自定义类也可使用sorted函数调用

 

简短拆包

亟待证实的是拆包能够行使到其它可迭代对象上。
先看最简易的拆包,平行赋值

lax_coordinates = (33.9425, -118.408056)
latitude, longitude = lax_coordinates
latitude
Out[10]: 
33.9425
longitude
Out[11]: 
-118.408056

利用平行赋值简便的交流八个变量的值

a=2
b=3
a,b=b,a
a
Out[15]: 
3
b
Out[16]: 
2

*能够用俩处理剩下的成分

a,b,*rest = range(6)
a
Out[19]: 
0
rest
Out[20]: 
[2, 3, 4, 5]
b
Out[21]: 
1

a,*rest,b = range(6)
a
Out[23]: 
0
b
Out[24]: 
5
rest
Out[25]: 
[1, 2, 3, 4]

python高级体系文章目录

python高级——目录

 

 

bisect

'''
    bisect模块主要用来管理有顺序的序列
    bisect模块包含的主要函数是bisect和insort,两个函数都使用二叉树方法搜索
    1、bisect(haystack, needle)
        haystack必须是一个有序的序列,该函数搜索needle在haystack中的位置,该位置使得将needle插入后haystack仍然升序
        查找到位置后可用haystack.insert()插入

    2、insort(seq, item)
        把item插入到seq中,并能保持seq的升序

'''

#  本人认为《流畅的python》中的对该模块介绍的例子比较经典,故引用之

# 1、关于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)


    '''   输出如下
    DEMO: bisect
    haystack ->  1  4  5  6  8 12 15 20 21 23 23 26 29 30
    31 @ 14      |  |  |  |  |  |  |  |  |  |  |  |  |  |31
    30 @ 14      |  |  |  |  |  |  |  |  |  |  |  |  |  |30
    29 @ 13      |  |  |  |  |  |  |  |  |  |  |  |  |29
    23 @ 11      |  |  |  |  |  |  |  |  |  |  |23
    22 @  9      |  |  |  |  |  |  |  |  |22
    10 @  5      |  |  |  |  |10
     8 @  5      |  |  |  |  |8 
     5 @  3      |  |  |5 
     2 @  1      |2 
     1 @  1      |1 
     0 @  0    0 
    '''
# 另,bisect.bisect函数有两个可选参数——lo和hi来缩小搜索范围,lo的默认值是0,hi的默认值是序列的长度
# 再另,bisect.bisect函数其实是bisect_right函数的别名,还有一个bisect_left,插入位置如果有相等的元素时,插入元素会放在它相等的
#      元素后面,后者会放在前面


# 根据分数,查到等级

def grade(score, breakpoints=[60, 70, 80, 90], grades = 'FDCBA'):
    i = bisect.bisect(breakpoints, score)     # 这里的bisect.bisect实际上使用的是bisect_right
    return grades[i]

print([grade(score) for score in [33, 55, 90, 87, 65, 78, 34, 60, 100]])

# 2、关于bisect.insort函数

import bisect
import random

SIZE = 7

random.seed(1729)

my_list = []
for i in range(SIZE):
    new_item = random.randrange(SIZE*2)
    bisect.insort(my_list, new_item)
    print('%2d ->' % new_item, my_list)

    '''输出:
    10 -> [10]
     0 -> [0, 10]
     6 -> [0, 6, 10]
     8 -> [0, 6, 8, 10]
     7 -> [0, 6, 7, 8, 10]
     2 -> [0, 2, 6, 7, 8, 10]
    10 -> [0, 2, 6, 7, 8, 10, 10]
    '''

# 另,insort函数也有insort_left,背后使用的是bisect_left

python内置系列类型,python内置类别类型 本文首要内容 连串类型分类:
(1)容器类别、扁平体系 (2)可变类别、不可…

嵌套拆包

拆包还能嵌套举行,这几个时候需求专注表明式的嵌套结构要和元组的嵌套结构同样

    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)),
        ('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
        ('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833)),]

    print('{:15} | {:^9} | {:^9}'.format('', 'lat.', 'long.'))
    fmt = '{:15} | {:9.4f} | {:9.4f}'
    for name, cc, pop, (latitude, longitude) in metro_areas:
        if longitude <= 0:
            print(fmt.format(name, latitude, longitude))

上述代码输出如下

                |   lat.    |   long.  
Mexico City     |   19.4333 |  -99.1333
New York-Newark |   40.8086 |  -74.0204
Sao Paulo       |  -23.5478 |  -46.6358

具名元组

作为记录使用,大家广大时候希望要有2个字段名,固然元组本人不也许知足要求,不过足以应用库中的collections.namedtuple来促成。collections.namedtuple
是三个工厂函数,它能够用来营造1个带字段名的元组和三个盛名字的类。

>>> from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates')
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
>>> tokyo
City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
>>> tokyo.population
36.933
>>> tokyo.coordinates
(35.689722, 139.691667)
>>> tokyo[1]
'JP'
>>> 

具名元组还有一部分蓄意的属性和方法:

>>> City._fields
('name', 'country', 'population', 'coordinates')
>>> 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))])
>>> for key, value in delhi._asdict().items():
    print(key + ':', value)


name: Delhi NCR
country: IN
population: 21.935
coordinates: LatLong(lat=28.613889, long=77.208889)

_田野先生s属性是3个涵盖这么些类具有字段名称的元组,_make()方法能够经受四个可迭代对象来生成那些类的3个实例,_asdict()
把具名元组以collections.OrderedDict 的花样重临。

切片

切开的成效学过python的都询问,那里最首要涉嫌部分切片必要留意的地点。

切片会忽略最终一个要素

那复合python和C都是0作为开局是适合的

>>> s = [1,2,3,4,5,6]
>>> s[1:3]
[2, 3]

对指标开始展览切开

还是能够用s[a:b:c]的样式对s在a和b之间以c为距离取值,c的值能够为负,这时为反向取值

>>> s = [1,2,3,4,5,6,7,8,9,10]
>>> s[1:9:2]
[2, 4, 6, 8]
>>> s[9:1:-2]
[10, 8, 6, 4]
>>> s[::-1]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

a:b:c那种用法的精神是在调用slice(start,stop,step),对seq[start:stop:step]
进行求值的时候,Python 会调用
seq._getitem_(slice(start, stop, step))。

给切片赋值

切开还有二个有力的法力便是能够一贯给切片赋值以修改原体系。

>>> s = list(range(10))
>>> s
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> s[3:6] = [10,20]
>>> s
[0, 1, 2, 10, 20, 6, 7, 8, 9]
>>> s[1:3] = [30,40,50,60]
>>> s
[0, 30, 40, 50, 60, 10, 20, 6, 7, 8, 9]
>>> s[1:5] = 20
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    s[1:5] = 20
TypeError: can only assign an iterable
>>> s[1:5] = [20]
>>> s
[0, 20, 10, 20, 6, 7, 8, 9]

从上边代码能够看到,给切片复值的值必须也是类别,哪怕唯有叁个值,也要用系列的款型。

对队列使用+和*

+和*都以对队列的拼凑操作,+和*操作不会修改原类别,而是转变二个新的队列。

>>> s1 = [1,2,3]
>>> s2 = [4,5,6]
>>> s1 + s2
[1, 2, 3, 4, 5, 6]
>>> s1
[1, 2, 3]
>>> s1 * 4
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> s1
[1, 2, 3]
>>> 3*s2
[4, 5, 6, 4, 5, 6, 4, 5, 6]
>>> s2
[4, 5, 6]
>>> 

*关于内需小心的有个别:要是系列内的成分是其余可变对象的引用的话,就必要尤其小心了。看上面那一个由列表构成列表的例证\

成立3个由列表组成的列表,大家或然会写出下边那样的代码

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

如此的结果会是怎么着,大家看下每步的结果:

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

一心不是我们想要的结果,为什么会出现那种现象?那里首先步中的[['_'] * 3]会形成体系[['_', '_', '_']],而[['_', '_', '_']]*3形成的五个体系都是那么些行列的引用,所以就会出现上边的意况。
毋庸置疑的做法应该像下边那样:

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

队列的增量赋值

增量赋值原理上都是同一的,那里关键集聚在+=上。
+=操作背后实际上是调用了_iadd方法,如若3个类没有落到实处那些法子的话,Python
会退一步调用 _
add**
方法。同时,可变体系就地转移,不可变连串会变卦二个新的靶子。

>>> s=[1,2,3]
>>> id(s)
48702528
>>> s+=[4,5,6]
>>> s
[1, 2, 3, 4, 5, 6]
>>> id(s)
48702528
>>> s*=3
>>> s
[1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]
>>> id(s)
48702528
>>> t=(1,2,3)
>>> id(t)
48765168
>>> t+=(4,5,6)
>>> t
(1, 2, 3, 4, 5, 6)
>>> id(t)
48202224

三个关于+=的牢笼

上面那段代码执行后会发生什么样动静

>>> t = (1,2,[3,4])
>>> t[2] += [5,6]

深信不疑广大人都领悟会抛出特别,因为元组是不足变类别。我们来看看执行结果,的确如此

>>> t = (1,2,[3,4])
>>> t[2] += [5,6]
Traceback (most recent call last):
  File "<pyshell#56>", line 1, in <module>
    t[2] += [5,6]
TypeError: 'tuple' object does not support item assignment

再看看今后t的值吗?

>>> t
(1, 2, [3, 4, 5, 6])

t的值也转移了,这是怎么回事呢?大家使用Python
Tutor(http://www.pythontutor.com)这么些可视化分析工具来探视运维情状。(这里强烈推荐这一个工具,可以动态呈现每句代码执行后相继变量的生成处境)。

威尼斯人线上娱乐 6

此处写图片描述

再来看六柱预测应的专擅的字节码

>>> import dis
>>> dis.dis('s[a]+=b')
  1           0 LOAD_NAME                0 (s)
              2 LOAD_NAME                1 (a)
              4 DUP_TOP_TWO
              6 BINARY_SUBSCR
              8 LOAD_NAME                2 (b)
             10 INPLACE_ADD
             12 ROT_THREE
             14 STORE_SUBSCR
             16 LOAD_CONST               0 (None)
             18 RETURN_VALUE

首先将 s[a] 的值存入 TOS(栈的上方),然后总结 TOS +=
b。这一步能够形成,是因为 TOS 指向的是八个可变对象,最后s[a] = TOS
赋值。这一步战败,是因为 s 是不可变的元组。

排序和摸索

排序

list.sort会对列表实行当庭排序,而python的放权函数sorted则是重新创造2个指标回来,它接受其余可迭代对象作为参数。

>>> s=[3,5,2,1,6,7,9,8]
>>> s_new = sorted(s)
>>> s
[3, 5, 2, 1, 6, 7, 9, 8]
>>> s_new
[1, 2, 3, 5, 6, 7, 8, 9]
>>> s.sort()
>>> s
[1, 2, 3, 5, 6, 7, 8, 9]

搜索

排过序的行列能够拓展二分查找,python标准库的嵌入模块 bisect
提供了二分查找算法。bisect(haystack, needle) 在
haystack里摸索needle的岗位,该岗位满意的准绳是,把 needle
插入那几个职分然后,haystack 还是可以够保全升序。

>>> bisect.bisect(s,3)
3
>>> bisect.bisect(s,8)
7
>>> bisect.bisect(s,8.5)
7

用bisect.insort仍是能够在多个不变的行列里插入新因素从而保障连串依然一如既往。

>>> bisect.insort(s,8.5)
>>> s
[1, 2, 3, 5, 6, 7, 8, 8.5, 9]

列表之外的精选

列表就算灵活而且不难,不过有个别时候面对各个必要的时候,大家大概还有更好的选料。当数据量较大时,比如,要存放
一千万个浮点数的话,数组(array)的作用要高得多,因为数组在背后存的并不是
float 对象,而是数字的机械翻译,也正是字节表述。那点就跟 C
语言中的数组一样。

数组

假使大家须要三个只包蕴数字的列表,那么 array.array 比 list
更高速。同时,数组不仅囊括 .pop、.insert
和.extend,还提供从文件读取和存入文件的更快的章程,如.frombytes 和
.tofile。

创办一个array时,要求钦点其系列,那些项目的记号与相应的门类的对应关系在标准库中可见查到。

上边包车型客车事例体现了从创设四个有 1000万个随机浮点数的数组开首,到何等把那个数组存放到文件里,再到什么从文件读取那么些数组。

>>> from array import array
>>> from random import random
>>> floats = array('d', (random() for i in range(10**7)))
>>> floats[-1]
0.4628972061976403
>>> 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.4628972061976403
>>> floats2 == floats
True

内部存款和储蓄器视图

memoryview
是二个内置类,它能让用户在不复制内容的景况下操作同二个数组的不如切片。memoryview.cast
的定义跟数组模块类似,能用不一样的艺术读写同一块内部存款和储蓄器数据,而且内容字节不会随机活动。那与C语言中的类型转换差不离。

>>> numbers = array('h', [-2, -1, 0, 1, 2])
>>> memv = memoryview(numbers)
>>> len(memv)
5
>>> memv[0]
-2
>>> memv_oct = memv.cast('B')
>>> memv_oct
<memory at 0x02E71E68>
>>> memv_oct.tolist()
[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]
>>> memv_oct[5] = 4
>>> numbers
array('h', [-2, -1, 1024, 1, 2])
>>>

此处运用含有 5 个短整型有号子整数的数组(类型码是
‘h’)成立二个memoryview,然后创造1个 memv_oct,那三回是把 memv
里的剧情转换来 ‘B’ 类型,也等于无符号字符。把放在地方 5 的字节赋值成
4,因为大家把占 2 个字节的平头的上位字节改成了
4,所以那几个有标志整数的值就变成了 1024。

双端队列

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.rotate(-4)
>>> dq
deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
>>> dq.appendleft(-1)
>>> dq
deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.extend([11, 22, 33])
>>> dq
deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)
>>> dq.extendleft([10, 20, 30, 40])
>>> dq
deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10)
>>>

maxlen
是1个可选参数,设定之后就不能够修改,当队列中的成分超出这么些值之后,就会自动删除多出的要素,如若从左端参与,就删除最右端的,要是从最右端参预,则从最左端删除。extendleft()方法是迭代安排的,所以插入后的逐条与原本的是相反的。

除此以外,append 和 popleft 都是原子操作,也即便得 deque 能够在多线程程序
中安全地作为先进先出的栈使用,而使用者不需求担心能源锁的难点。


相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图