微信公众号:码农充电站pro
我的主页:https://codeshellme.github.iohtml
若是你发现特殊状况太多,那极可能是用错算法了。
—— Carig Zerounipython
目录git
前几节咱们介绍了Python 中四种数据结构的特性和基本用法,本节介绍与数据结构相关的高级特性。github
Python 序列是指,其中存放的元素是有序排列
的,可用下标访问,字符串
,列表
,元组
都是序列。算法
而字典
与集合
中的元素是无序排列的,所以通常不归在序列
中。shell
Python 序列有以下特色:微信
不可变
类型下标
访问,下标可正可负切片
访问部分连续
元素相加
,相乘
,in 运算
for 循环
遍历全部元素可使用collections
模块中的Sequence
类来查看一个对象是不是一个序列:数据结构
>>> isinstance('', collections.Sequence) # 字符串是序列 True >>> isinstance([], collections.Sequence) # 列表是序列 True >>> isinstance((), collections.Sequence) # 元组是序列 True >>> isinstance({}, collections.Sequence) # 字典不是序列 False >>> isinstance(set(), collections.Sequence) # 集合不是序列 False
提示:app
1,
isinstance
函数用于查看一个对象属于某个类函数2,在使用
模块
时,要先import
该模块
可迭代类型
咱们知道str
,list
,tuple
,dict
,set
均可用for 循环
来遍历,这个遍历的过程就是一个迭代
过程,这些类型都是可迭代
类型。
可迭代的类型,都实现了__iter__
方法,咱们经过dir(可迭代对象)
,能够看到,可迭代对象的魔法方法
中都有一个__iter__
方法。
咱们也能够经过collections
模块中的Iterable
类型来查看一个对象是否是可迭代对象:
>>> isinstance('', collections.Iterable) True >>> isinstance([], collections.Iterable) True >>> isinstance((), collections.Iterable) True >>> isinstance({}, collections.Iterable) True >>> isinstance(set(), collections.Iterable) True
迭代器
迭代器
是一种可迭代
的对象。
迭代器必定是可迭代的,可迭代的对象不必定是迭代器。
迭代器要实现两个魔法方法:__iter__
和 __next__
。
经过collections
模块中的Iterator
类型来查看这两个方法:
>>> dir(collections.Iterator)
判断一个对象是否是迭代器:
>>> isinstance('', collections.Iterator) # 字符串不是迭代器 False >>> isinstance([], collections.Iterator) # 列表不是迭代器 False >>> isinstance((), collections.Iterator) # 元组不是迭代器 False >>> isinstance({}, collections.Iterator) # 字典不是迭代器 False >>> isinstance(set(), collections.Iterator) # 集合不是迭代器 False
迭代器有一些通用函数,下面咱们介绍一些经常使用的。
1.enumerate
函数
在Python3 中,enumerate
其实是一个类
,可经过help(enumerate)
查看,也能够把它当作函数来使用。
其常常被用在for 循环
中,便可遍历下标,又能遍历数据。
做用: 用于给一个
可迭代
的对象,添加下标
原型: enumerate(iterable[, start]) -> iterator
参数 iterable: 一个可迭代的对象
参数 start: 下标起始位置
返回值: 一个enumerate
对象,同时也是一个迭代器
示例:
>>> l = enumerate(['a', 'c', 'b']) # 参数是一个列表 >>> type(l) <class 'enumerate'> >>> isinstance(l, collections.Iterator) # 是一个迭代器 True >>> for index, item in l: # for 循环遍历,能遍历出下标 ... print(index, item) ... 0 a 1 c 2 b
2.iter
函数
做用:将一个可迭代的序列
iterable
转换成迭代器
原型:iter(iterable) -> iterator
参数:iterable 是一个可迭代的序列
返回值:一个迭代器
示例:
>>> iter('123') # 参数是字符串 <str_iterator object at 0x7fcb7dd320b8> # str 迭代器 >>> iter([1, 2, 3]) # 参数是列表 <list_iterator object at 0x7fcb7dd4a0b8> # list 迭代器 >>> iter((1, 2, 3)) # 参数是元组 <tuple_iterator object at 0x7fcb7dd4a0b8> # tuple 迭代器 >>> iter(set([1, 2, 3])) # 参数是集合 <set_iterator object at 0x7fcb7d2c5e10> # set 迭代器 >>> iter({'a':1, 'b':2}) # 参数是字典 <dict_keyiterator object at 0x7fcb7f467098> # dict 迭代器
3.next
函数
做用:返回迭代器的下一个元素
原型:next(iterator[, default]) -> item
参数 iterator:是一个迭代器类型
参数 default:任意类型数据,可省
返回值:当
迭代器中有元素
时:返回迭代器中的下一个元素
当迭代器中没有元素
且没有default 参数
时:抛出StopIteration
异常
当迭代器中没有元素
且有default 参数
时:返回default
示例:
>>> i = iter([1, 3, 5]) # i 是一个迭代器 >>> next(i) # 返回 1 1 >>> next(i) # 返回 3 3 >>> next(i) # 返回 5 5 >>> next(i) # i 中没有元素,抛出异常 Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration >>> >>> next(i, 7) # i 中没有元素,返回第二个参数 7 7
4.len
函数
做用:用于计算一个对象
obj
中的元素的个数
原型:len(obj, /)
参数:通常obj
是一个可迭代类型对象,实际上,只要实现了__len__
方法的对象,均可以使用该函数
返回值:一个整数
示例:
>>> len('abc') 3 >>> len([1, 2, 3]) 3
5.max
函数
做用:返回可迭代对象
iterable
中的最大元素
原型:max(iterable)
参数:iterable
是一个可迭代的对象,而且iterable
中的元素可比较
返回值:最大值
示例:
>>> max([1, 2]) 2 >>> max([1, 2, 3]) 3 >>> max('b', 'a') 'b' >>> max('abc') 'c' >>> max(1, 'a') # 整数与字符串不是同类型,不可比较 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: '>' not supported between instances of 'str' and 'int'
6.min
函数
做用:返回可迭代对象
iterable
中的最小元素
原型:min(iterable)
参数:iterable
是一个可迭代的对象,而且iterable
中的元素可比较
返回值:最小值
示例:
>>> min([1, 2]) 1 >>> min([2, 3]) 2 >>> min('abc') 'a' >>> min('b', 'c') 'b' >>> min('b', 2) # 整数与字符串不是同类型,不可比较 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: '<' not supported between instances of 'int' and 'str'
7.sum
函数
做用:计算可迭代对象
iterable
中的数据之和,最后在加上start
原型:sum(iterable, start=0, /)
参数:iterable
是一个可迭代对象,其中的元素是数字类型
返回值:全部元素之和
示例:
>>> sum([1, 2, 3]) # 计算 1,2,3 之和 6 >>> sum([1, 2, 3], 5) # 计算 1,2,3 之和,再加上 5 11
8.reversed
函数
reversed
其实是一个类,可用help(reversed)
查看。
做用:将一个序列
sequence
反转
原型:reversed(sequence)
参数:sequence
是一个序列类型
返回值:一个reversed
对象,该对象也是一个迭代器
,可被迭代
示例:
>>> r = reversed('abcde') >>> r # 一个 reversed 对象 <reversed object at 0x7fcb79970518> >>> isinstance(r, collections.Iterator) # 也是一个迭代器 True >>> [i for i in r] # 转换成列表,查看其中的元素 ['e', 'd', 'c', 'b', 'a'] >>> >>> r = reversed([1, 3, 5, 7]) >>> [i for i in r] [7, 5, 3, 1]
列表生成式
,又叫列表推导式
,用于从一个可迭代对象
生成一个列表
,它是一种代码简写形式,其优势是代码简洁优雅。
好比,咱们有一个列表 [1, 3, 5]
,想求其中每一个元素的平方,再将结果放入列表中,最终的结果是[1, 9, 25]
。
若是是通常的方式,咱们写出来的代码是这样的:
l = [1, 3, 5] l2 = [] for i in l: item = i * i l2.append(item) print(l2)
若是用列表生成式的方式,代码是这样的:
l = [1, 3, 5] l2 = [i * i for i in l] print(l2)
能够看到列表生成式比普通的形式要简洁许多。
列表生成式语法
最简单的列表生成式的语法,就像上面的代码同样:
列表生成式
由三部分组成:
[]
item
有关,也可无关可迭代对象
列表生成式中的if
判断
列表生成式中也能够有if
判断,当判断条件
成立时,才会执行表达式,并将该表达式的结果append
到新的列表中。
这里的if
判断没有else
部分,判断条件
通常与item
有关。
以下:
示例:
l = [1, 3, 5] # 只有当 l 中的元素大于 1 时,才算平方 l2 = [i * i for i in l if i > 1] print(l2)
range
函数
在Python2.x 中
,range
是一个函数
。
在Python3.x
中,range
是一个类
,可用help(range)
查看其手册。
>>> range <class 'range'>
下面介绍Python3.x
中range
的用法,有两种参数形式:
做用:生成一个从
start
到stop
的,步长为step
的,可迭代的整数序列,该序列包含start
,不包含stop
,即遵循左开右闭
原则
原型:range(stop) -> range object
range(start, stop[, step]) -> range object参数:
当只有
stop
参数时,该序列从0
开始到stop
,步长为1
当有start
和stop
参数时,该序列从start
开始到stop
,步长为1
当有step
参数时,步长为step
返回值:一个
range
对象
示例:
>>> range(5) range(0, 5) >>> range(1, 5) range(1, 5) >>> range(1, 5, 2) range(1, 5, 2)
range
对象是一个序列,而不是一个迭代器:
>>> isinstance(range(5), collections.Sequence) True >>> isinstance(range(5), collections.Iterator) False
可使用列表生成式
来查看range
中的内容:
>>> [i for i in range(5)] # 从 0 到 5 [0, 1, 2, 3, 4] >>> [i for i in range(1, 5)] # 从 1 到 5 [1, 2, 3, 4] >>> [i for i in range(1, 5, 2)] # 步长为 2 [1, 3]
生成器也是一个迭代器
。生成器跟列表有点像,但优势是比列表节省内存
。
对于列表,Python 会为列表中的每一个元素都分配实实在在的内存空间,若是列表中的元素不少,那么列表将消耗大量内存。
而对于生成器,Python 并不会为其中的每一个元素都分配内存。
生成器记录的是一种算法,是如何生成数据的算法,在每次用到数据时,才会去生成数据,而不会一开始就将全部的数据准备好。
所以,对于相同的功能,生成器
和列表
都能完成,而生成器能够节省大量的内存。
建立生成器有两种方式:
列表生成式
中的中括号[]
改成小括号()
yield
关键字使用列表生成式
以下代码能够生成一个列表:
>>> [i for i in range(5)] [0, 1, 2, 3, 4]
将中括号[]
改成小括号()
,就是一个生成器:
>>> l = (i for i in range(5)) >>> l <generator object <genexpr> at 0x7f3433d2d9e8> >>> type(l) <class 'generator'> >>> isinstance(l, collections.Iterator) # 生成器也是一个迭代器 True
其中的generator
就是生成器的意思,它也是一个类
。
使用yield
关键字
好比,咱们想计算列表[1, 3, 5]
中每一个元素的平方,使用yield
关键字,代码以下:
#! /usr/bin/env python3 def test(): print('test...') l = [1, 3, 5] for i in l: tmp = i * i print('yield tmp:%s' % tmp) yield tmp t = test() print(t) # <generator object test at 0x7fde1cdaa3b8> print(type(t)) # <class'generator'>
注意,咱们定义了一个函数,这里咱们只是为了演示如何使用yield
来建立生成器,而不用过多关注如何定义函数。
函数
的概念咱们会在后续章节详细介绍。
执行以上代码,输出以下:
<generator object test at 0x7fde1cdaa3b8> <class'generator'>
你会发现,字符串test...
并无被打印出来。
你可能会有疑问,既然代码t = test()
已经执行了,那整个test()
函数中的代码都应该执行完了才对,那字符串test...
怎么会没有打印呢?
那是由于,生成器
中代码的执行是惰性
的。当执行t = test()
这行代码时,test()
函数并无被执行。
前边咱们说过,生成器记录的是一个算法
,而不是真正的数据,数据只有当使用到的时候,才会去生成。
因此,变量 t
中只是一个算法,而没有数据。
由于,生成器也是一个迭代器,因此生成器可使用next()
函数来访问其中的数据:
i = next(t) print('i value is', i)
执行上面这行代码后,程序会输出:
test... yield tmp:1 i value is 1
字符串test...
被打印,说明test()
执行了。
当代码执行到yield
时,变量i
会接收到yield
返回的数据,此时,代码会从yield
处跳出test()
函数。
若是接下来,再也不遍历变量t
中的数据,那么整个代码就执行结束了。
若是咱们再次执行代码:
j = next(t) print('j value is', j)
程序会输出:
yield tmp:9 j value is 9
可见代码会在上次yield
的地方,再次向下执行。
咱们再次执行代码:
k = next(t) print('k value is', k)
程序会输出:
yield tmp:25 k value is 25
当t
中的元素被遍历完后,若是再次执行next(t)
,则会抛出StopIteration
异常。
使用next()
函数来遍历生成器中的全部元素是很麻烦的,咱们能够像遍历列表同样,用for 循环
来遍历生成器中的元素:
for i in t: print(i)
输出以下:
test... yield tmp:1 1 yield tmp:9 9 yield tmp:25 25
整个遍历过程当中,字符串test...
只被输出了一次,并无被输出三次。
说明当代码执行到yield
时,并无从函数test()
中返回,代码只是暂停在了yield
处,等下次须要数据时,会接着从上次的yield
处接着执行。
生成器比列表节省内存
若是咱们想生成一个从0
到9999
的数字序列,用列表的话,是这样的:
>>> l = [i for i in range(10000)] >>> sys.getsizeof(l) # 内存占用 87624 字节 87624
sys
模块的getsizeof
方法能够查看一个对象的大小,单位是字节
。
用生成器来实现的话,是这样的:
>>> l = (i for i in range(10000)) >>> sys.getsizeof(l) # 内存占用 88 字节 88
能够看到0
到9999
这样的整数序列,使用列表的话,占用 87624
字节;使用生成器的话,只占用 88
字节
咱们已经知道了,Python3 中的str
,list
,tuple
,dict
,set
都是一个类:
>>> type('') <class 'str'> >>> type([]) <class 'list'> >>> type(()) <class 'tuple'> >>> type({}) <class 'dict'> >>> type(set()) <class 'set'>
每一个类都有构造方法
,这些构造方法能够将其它类型的数据,转换
成该类型数据,咱们也能够将这种转换称为强制类型转换
。
提示:
构造方法
是一个类
的初始化方法,就是用什么样的数据去构造一个特定类的对象。当介绍到
类与对象
时,咱们会详细介绍。
str
强制转换
做用: 将其它类型数据转换成字符串
原型: str(object='') -> str
参数: 任意类型数据
返回值: 字符串
示例:
>>> str(1) # 将数字转换成字符串 '1' >>> str([1, 2]) # 将列表转换成字符串 '[1, 2]' >>> str((1, 2)) # 将元组转换成字符串 '(1, 2)'
list
强制转换
做用: 将一个可迭代类型转成列表
原型: list(iterable) -> list
参数: 任意可迭代类型数据
返回值: 列表
示例:
>>> list((1, 2)) # 将一个元组转成列表 [1, 2] >>> list(range(3)) # 将一个 range 对象转成列表 [0, 1, 2]
tuple
强制转换
做用: 将一个可迭代类型转成元组
原型: tuple(iterable) -> tuple
参数: 任意可迭代类型数据
返回值: 元组
示例:
>>> tuple([1, 2]) # 将一个列表转成元组 (1, 2) >>> tuple(range(3)) # 将一个 range 对象转成元组 (0, 1, 2)
dict
强制转换
做用: 将一个可迭代类型数据转成字典
原型: dict(iterable) -> dict
参数:iterable
是一个可迭代对象,而且该对象中的元素是元组
返回值: 字典
示例:
>>> t = ((1, 2), (2, 3)) # t 是一个元组,其中的元素也是元组 >>> dict(t) {1: 2, 2: 3} >>> >>> l = [(1, 2), (2, 3)] # l 是一个列表,其中的元素是元组 >>> dict(l) {1: 2, 2: 3}
set
强制转换
做用: 将一个可迭代类型数据转成集合
原型: set(iterable) -> set
参数: 一个可迭代对象
返回值: 集合
其实,咱们在介绍集合
时,都是用的这种方式来声明的集合,示例:
>>> set('abc') # 将一个字符串转成集合 {'b', 'c', 'a'} >>> set([0, 1]) # 将一个列表转成集合 {0, 1} >>> set((0, 1)) # 将一个元组转成集合 {0, 1}
(完。)
推荐阅读:
欢迎关注做者公众号,获取更多技术干货。