微信公众号:码农充电站pro

个人主页:https://codeshellme.github.io

如果你发现特殊情况太多,那很可能是用错算法了。

—— Carig Zerouni

目录

前几节我们介绍了Python 中四种数据结构的特性和基本用法,本节介绍与数据结构相关的高级特性。

  • 序列
  • 迭代器
  • 列表生成式
  • 生成器
  • 强制类型转换

1,序列

Python 序列是指,其中存放的元素是有序排列的,可用下标访问,字符串列表元组都是序列。

字典集合中的元素是无序排列的,因此一般不归在序列中。

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

提示:

1,isinstance 函数用于查看一个对象属于某个类

2,在使用模块时,要先import 该模块

2,迭代器

可迭代类型

我们知道strlisttupledictset 都可用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]

3,列表生成式

列表生成式,又叫列表推导式,用于从一个可迭代对象生成一个列表,它是一种代码简写形式,其优点是代码简洁优雅。

比如,我们有一个列表 [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 有关,也可无关
  • for 循环:用于迭代原始可迭代对象

列表生成式中的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.xrange 的用法,有两种参数形式:

作用:生成一个从startstop 的,步长为step 的,可迭代的整数序列,该序列包含start,不包含stop,即遵循左开右闭原则

原型

range(stop) -> range object

range(start, stop[, step]) -> range object

参数

当只有stop 参数时,该序列从0 开始到stop,步长为1

当有startstop 参数时,该序列从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]

4,生成器

生成器也是一个迭代器。生成器跟列表有点像,但优点是比列表节省内存

对于列表,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 处接着执行。

生成器比列表节省内存

如果我们想生成一个从09999 的数字序列,用列表的话,是这样的:

>>> 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

可以看到09999 这样的整数序列,使用列表的话,占用 87624 字节;使用生成器的话,只占用 88 字节

5,强制类型转换

我们已经知道了,Python3 中的strlisttupledictset 都是一个类:

>>> 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}

(完。)


推荐阅读:

Python 简明教程 --- 9,Python 编码

Python 简明教程 --- 10,Python 列表

Python 简明教程 --- 11,Python 元组

Python 简明教程 --- 12,Python 字典

Python 简明教程 --- 13,Python 集合


欢迎关注作者公众号,获取更多技术干货。

Python 简明教程 --- 14,Python 数据结构进阶的更多相关文章

  1. Python 简明教程 --- 18,Python 面向对象

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 代码能借用就借用. -- Tom Duff 目录 编程可分为面向过程编程和面向对象编程,它们是两种不 ...

  2. Python 简明教程 --- 15,Python 函数

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 测试只能证明程序有错误,而不能证明程序没有错误. -- Edsger Dijkstra 目录 本节我 ...

  3. Python 简明教程 --- 16,Python 高阶函数

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 对于那些快速算法,我们总是可以拿一些速度差不多但是更容易理解的算法来替代它们. -- Douglas ...

  4. Python 简明教程 --- 17,Python 模块与包

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 正确的判断来源于经验,然而经验来源于错误的判断. -- Fred Brooks 目录 我们已经知道函 ...

  5. Python 简明教程 --- 19,Python 类与对象

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 那些能用计算机迅速解决的问题,就别用手做了. -- Tom Duff 目录 上一节 我们介绍了Pyt ...

  6. python简明教程

    Python简明教程 MachinePlay关注 0.7072018.09.26 01:49:43字数 2,805阅读 9,287 Python一小时快速入门 1.Python简介   pylogo. ...

  7. Python 简明教程 --- 13,Python 集合

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 如果代码和注释不一致,那很可能两者都错了. -- Norm Schryer 目录 前几节我们已经介绍 ...

  8. 《Python简明教程》总结

    Python经典教程<Python简明教程> 目录: 为什么Python 安装Python 体验Python Python数据类型 运算符与表达式 控制流 函数 模块 数据结构 解决问题 ...

  9. Python 简明教程 --- 2,第一个Python 程序

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 如果你发现特殊情况太多,那你肯定是用错方法了. -- Carig Zerouni 当你在自己的电脑上 ...

随机推荐

  1. Parrot os安装docker及docker-compose

    一.安装docker 1.添加Docker pgp key curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key ...

  2. 【大厂面试03期】MySQL是怎么解决幻读问题的?

    问题分析 首先幻读是什么? 根据MySQL文档上面的定义 The so-called phantom problem occurs within a transaction when the same ...

  3. Java实现 LeetCode 563 二叉树的坡度(又是一个遍历树)

    563. 二叉树的坡度 给定一个二叉树,计算整个树的坡度. 一个树的节点的坡度定义即为,该节点左子树的结点之和和右子树结点之和的差的绝对值.空结点的的坡度是0. 整个树的坡度就是其所有节点的坡度之和. ...

  4. Java实现 LeetCode 475 供暖器

    475. 供暖器 冬季已经来临. 你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖. 现在,给出位于一条水平线上的房屋和供暖器的位置,找到可以覆盖所有房屋的最小加热半径. 所以,你的输入将会是房 ...

  5. Java实现 LeetCode 372 超级次方

    372. 超级次方 你的任务是计算 ab 对 1337 取模,a 是一个正整数,b 是一个非常大的正整数且会以数组形式给出. 示例 1: 输入: a = 2, b = [3] 输出: 8 示例 2: ...

  6. Java实现汉诺塔问题

    1 问题描述 Simulate the movement of the Towers of Hanoi Puzzle; Bonus is possible for using animation. e ...

  7. Java实现字符串转换成整数

    1 问题描述 输入一个由数字组成的字符串,请把它转换成整数并输出.例如,输入字符串"123",输出整数123. 请写出一个函数实现该功能,不能使用库函数. 2 解决方案 解答本问题 ...

  8. 数据结构&算法

    20个最常用.最基础数据结构与算法: 10个数据结构:数组.链表.栈.队列.散列表.二叉树.堆.跳表.图.Trie 树. 10个 算法      :递归.排序.二分查找.搜索.哈希.贪心.分治.回溯. ...

  9. JavaWeb+SVN+Maven+Tomcat +jenkins搭建持续集成环境和自动部署

    https://blog.csdn.net/wh52788/article/details/80900477 https://blog.csdn.net/liyong1028826685/articl ...

  10. 一篇文章教会你用Python抓取抖音app热点数据

    今天给大家分享一篇简单的安卓app数据分析及抓取方法.以抖音为例,我们想要抓取抖音的热点榜数据. 要知道,这个数据是没有网页版的,只能从手机端下手. 首先我们要安装charles抓包APP数据,它是一 ...