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

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

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

—— Carig Zerouni

目录

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

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

1,序列

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

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

Python 序列有如下特点:

  • 序列中的元素是不可变类型
  • 序列中的元素可用下标访问,下标可正可负
  • 可通过切片访问部分连续元素
  • 可进行相加相乘in 运算
  • 可通过for 循环遍历所有元素

可以使用collections 模块中的Sequence 类来查看一个对象是否是一个序列:

  1. >>> isinstance('', collections.Sequence) # 字符串是序列
  2. True
  3. >>> isinstance([], collections.Sequence) # 列表是序列
  4. True
  5. >>> isinstance((), collections.Sequence) # 元组是序列
  6. True
  7. >>> isinstance({}, collections.Sequence) # 字典不是序列
  8. False
  9. >>> isinstance(set(), collections.Sequence) # 集合不是序列
  10. False

提示:

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

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

2,迭代器

可迭代类型

我们知道strlisttupledictset 都可用for 循环来遍历,这个遍历的过程就是一个迭代过程,这些类型都是可迭代类型。

可迭代的类型,都实现了__iter__ 方法,我们通过dir(可迭代对象),可以看到,可迭代对象的魔法方法中都有一个__iter__ 方法。

我们也可以通过collections 模块中的Iterable 类型来查看一个对象是不是可迭代对象:

  1. >>> isinstance('', collections.Iterable)
  2. True
  3. >>> isinstance([], collections.Iterable)
  4. True
  5. >>> isinstance((), collections.Iterable)
  6. True
  7. >>> isinstance({}, collections.Iterable)
  8. True
  9. >>> isinstance(set(), collections.Iterable)
  10. True

迭代器

迭代器是一种可迭代的对象。

迭代器一定是可迭代的,可迭代的对象不一定是迭代器。

迭代器要实现两个魔法方法:__iter____next__

通过collections 模块中的Iterator 类型来查看这两个方法:

  1. >>> dir(collections.Iterator)

判断一个对象是不是迭代器:

  1. >>> isinstance('', collections.Iterator) # 字符串不是迭代器
  2. False
  3. >>> isinstance([], collections.Iterator) # 列表不是迭代器
  4. False
  5. >>> isinstance((), collections.Iterator) # 元组不是迭代器
  6. False
  7. >>> isinstance({}, collections.Iterator) # 字典不是迭代器
  8. False
  9. >>> isinstance(set(), collections.Iterator) # 集合不是迭代器
  10. False

迭代器通用函数

迭代器有一些通用函数,下面我们介绍一些常用的。

1.enumerate 函数

在Python3 中,enumerate 实际上是一个,可通过help(enumerate) 查看,也可以把它当做函数来使用。

其经常被用在for 循环中,即可遍历下标,又能遍历数据。

作用: 用于给一个可迭代的对象,添加下标

原型: enumerate(iterable[, start]) -> iterator

参数 iterable: 一个可迭代的对象

参数 start: 下标起始位置

返回值: 一个enumerate 对象,同时也是一个迭代器

示例:

  1. >>> l = enumerate(['a', 'c', 'b']) # 参数是一个列表
  2. >>> type(l)
  3. <class 'enumerate'>
  4. >>> isinstance(l, collections.Iterator) # 是一个迭代器
  5. True
  6. >>> for index, item in l: # for 循环遍历,能遍历出下标
  7. ... print(index, item)
  8. ...
  9. 0 a
  10. 1 c
  11. 2 b

2.iter 函数

作用:将一个可迭代的序列iterable 转换成迭代器

原型:iter(iterable) -> iterator

参数:iterable 是一个可迭代的序列

返回值:一个迭代器

示例:

  1. >>> iter('123') # 参数是字符串
  2. <str_iterator object at 0x7fcb7dd320b8> # str 迭代器
  3. >>> iter([1, 2, 3]) # 参数是列表
  4. <list_iterator object at 0x7fcb7dd4a0b8> # list 迭代器
  5. >>> iter((1, 2, 3)) # 参数是元组
  6. <tuple_iterator object at 0x7fcb7dd4a0b8> # tuple 迭代器
  7. >>> iter(set([1, 2, 3])) # 参数是集合
  8. <set_iterator object at 0x7fcb7d2c5e10> # set 迭代器
  9. >>> iter({'a':1, 'b':2}) # 参数是字典
  10. <dict_keyiterator object at 0x7fcb7f467098> # dict 迭代器

3.next 函数

作用:返回迭代器的下一个元素

原型:next(iterator[, default]) -> item

参数 iterator:是一个迭代器类型

参数 default:任意类型数据,可省

返回值

迭代器中有元素时:返回迭代器中的下一个元素

迭代器中没有元素没有default 参数时:抛出StopIteration 异常

迭代器中没有元素有default 参数时:返回default

示例:

  1. >>> i = iter([1, 3, 5]) # i 是一个迭代器
  2. >>> next(i) # 返回 1
  3. 1
  4. >>> next(i) # 返回 3
  5. 3
  6. >>> next(i) # 返回 5
  7. 5
  8. >>> next(i) # i 中没有元素,抛出异常
  9. Traceback (most recent call last):
  10. File "<stdin>", line 1, in <module>
  11. StopIteration
  12. >>>
  13. >>> next(i, 7) # i 中没有元素,返回第二个参数 7
  14. 7

4.len 函数

作用:用于计算一个对象obj中的元素的个数

原型:len(obj, /)

参数:一般obj 是一个可迭代类型对象,实际上,只要实现了__len__ 方法的对象,都可以使用该函数

返回值:一个整数

示例:

  1. >>> len('abc')
  2. 3
  3. >>> len([1, 2, 3])
  4. 3

5.max 函数

作用:返回可迭代对象iterable 中的最大元素

原型:max(iterable)

参数iterable 是一个可迭代的对象,并且iterable 中的元素可比较

返回值:最大值

示例:

  1. >>> max([1, 2])
  2. 2
  3. >>> max([1, 2, 3])
  4. 3
  5. >>> max('b', 'a')
  6. 'b'
  7. >>> max('abc')
  8. 'c'
  9. >>> max(1, 'a') # 整数与字符串不是同类型,不可比较
  10. Traceback (most recent call last):
  11. File "<stdin>", line 1, in <module>
  12. TypeError: '>' not supported between instances of 'str' and 'int'

6.min 函数

作用:返回可迭代对象iterable 中的最小元素

原型:min(iterable)

参数iterable 是一个可迭代的对象,并且iterable 中的元素可比较

返回值:最小值

示例:

  1. >>> min([1, 2])
  2. 1
  3. >>> min([2, 3])
  4. 2
  5. >>> min('abc')
  6. 'a'
  7. >>> min('b', 'c')
  8. 'b'
  9. >>> min('b', 2) # 整数与字符串不是同类型,不可比较
  10. Traceback (most recent call last):
  11. File "<stdin>", line 1, in <module>
  12. TypeError: '<' not supported between instances of 'int' and 'str'

7.sum 函数

作用:计算可迭代对象iterable 中的数据之和,最后在加上 start

原型:sum(iterable, start=0, /)

参数iterable 是一个可迭代对象,其中的元素是数字类型

返回值:所有元素之和

示例:

  1. >>> sum([1, 2, 3]) # 计算 1,2,3 之和
  2. 6
  3. >>> sum([1, 2, 3], 5) # 计算 1,2,3 之和,再加上 5
  4. 11

8.reversed 函数

reversed 实际上是一个类,可用help(reversed) 查看。

作用:将一个序列sequence 反转

原型:reversed(sequence)

参数sequence 是一个序列类型

返回值:一个reversed 对象,该对象也是一个迭代器,可被迭代

示例:

  1. >>> r = reversed('abcde')
  2. >>> r # 一个 reversed 对象
  3. <reversed object at 0x7fcb79970518>
  4. >>> isinstance(r, collections.Iterator) # 也是一个迭代器
  5. True
  6. >>> [i for i in r] # 转换成列表,查看其中的元素
  7. ['e', 'd', 'c', 'b', 'a']
  8. >>>
  9. >>> r = reversed([1, 3, 5, 7])
  10. >>> [i for i in r]
  11. [7, 5, 3, 1]

3,列表生成式

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

比如,我们有一个列表 [1, 3, 5],想求其中每个元素的平方,再将结果放入列表中,最终的结果是[1, 9, 25]

如果是一般的方式,我们写出来的代码是这样的:

  1. l = [1, 3, 5]
  2. l2 = []
  3. for i in l:
  4. item = i * i
  5. l2.append(item)
  6. print(l2)

如果用列表生成式的方式,代码是这样的:

  1. l = [1, 3, 5]
  2. l2 = [i * i for i in l]
  3. print(l2)

可以看到列表生成式比普通的形式要简洁许多。

列表生成式语法

最简单的列表生成式的语法,就像上面的代码一样:

列表生成式由三部分组成:

  • 列表符号:中括号[]
  • 表达式:用于生成新列表中的每个元素,一般与item 有关,也可无关
  • for 循环:用于迭代原始可迭代对象

列表生成式中的if 判断

列表生成式中也可以有if 判断,当判断条件成立时,才会执行表达式,并将该表达式的结果append 到新的列表中。

这里的if 判断没有else 部分,判断条件一般与item 有关。

如下:

示例:

  1. l = [1, 3, 5]
  2. # 只有当 l 中的元素大于 1 时,才算平方
  3. l2 = [i * i for i in l if i > 1]
  4. print(l2)

range 函数

Python2.x 中range 是一个函数

Python3.x 中,range 是一个,可用help(range) 查看其手册。

  1. >>> range
  2. <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 对象

示例:

  1. >>> range(5)
  2. range(0, 5)
  3. >>> range(1, 5)
  4. range(1, 5)
  5. >>> range(1, 5, 2)
  6. range(1, 5, 2)

range 对象是一个序列,而不是一个迭代器:

  1. >>> isinstance(range(5), collections.Sequence)
  2. True
  3. >>> isinstance(range(5), collections.Iterator)
  4. False

可以使用列表生成式来查看range 中的内容:

  1. >>> [i for i in range(5)] # 从 0 到 5
  2. [0, 1, 2, 3, 4]
  3. >>> [i for i in range(1, 5)] # 从 1 到 5
  4. [1, 2, 3, 4]
  5. >>> [i for i in range(1, 5, 2)] # 步长为 2
  6. [1, 3]

4,生成器

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

对于列表,Python 会为列表中的每个元素都分配实实在在的内存空间,如果列表中的元素很多,那么列表将消耗大量内存。

而对于生成器,Python 并不会为其中的每个元素都分配内存。

生成器记录的是一种算法,是如何生成数据的算法,在每次用到数据时,才会去生成数据,而不会一开始就将所有的数据准备好。

因此,对于相同的功能,生成器列表都能完成,而生成器可以节省大量的内存。

创建生成器有两种方式:

  • 列表生成式中的中括号[]改为小括号()
  • 在函数中使用yield 关键字

使用列表生成式

如下代码可以生成一个列表:

  1. >>> [i for i in range(5)]
  2. [0, 1, 2, 3, 4]

将中括号[] 改为小括号(),就是一个生成器:

  1. >>> l = (i for i in range(5))
  2. >>> l
  3. <generator object <genexpr> at 0x7f3433d2d9e8>
  4. >>> type(l)
  5. <class 'generator'>
  6. >>> isinstance(l, collections.Iterator) # 生成器也是一个迭代器
  7. True

其中的generator 就是生成器的意思,它也是一个

使用yield 关键字

比如,我们想计算列表[1, 3, 5] 中每个元素的平方,使用yield 关键字,代码如下:

  1. #! /usr/bin/env python3
  2. def test():
  3. print('test...')
  4. l = [1, 3, 5]
  5. for i in l:
  6. tmp = i * i
  7. print('yield tmp:%s' % tmp)
  8. yield tmp
  9. t = test()
  10. print(t) # <generator object test at 0x7fde1cdaa3b8>
  11. print(type(t)) # <class'generator'>

注意,我们定义了一个函数,这里我们只是为了演示如何使用yield 来创建生成器,而不用过多关注如何定义函数。

函数的概念我们会在后续章节详细介绍。

执行以上代码,输出如下:

  1. <generator object test at 0x7fde1cdaa3b8>
  2. <class'generator'>

你会发现,字符串test...并没有被打印出来。

你可能会有疑问,既然代码t = test() 已经执行了,那整个test() 函数中的代码都应该执行完了才对,那字符串test... 怎么会没有打印呢?

那是因为,生成器中代码的执行是惰性的。当执行t = test() 这行代码时,test() 函数并没有被执行。

前边我们说过,生成器记录的是一个算法,而不是真正的数据,数据只有当使用到的时候,才会去生成。

所以,变量 t 中只是一个算法,而没有数据。

因为,生成器也是一个迭代器,所以生成器可以使用next() 函数来访问其中的数据:

  1. i = next(t)
  2. print('i value is', i)

执行上面这行代码后,程序会输出:

  1. test...
  2. yield tmp:1
  3. i value is 1

字符串test... 被打印,说明test() 执行了。

当代码执行到yield 时,变量i 会接收到yield 返回的数据,此时,代码会从yield 处跳出test() 函数。

如果接下来,不再遍历变量t 中的数据,那么整个代码就执行结束了。

如果我们再次执行代码:

  1. j = next(t)
  2. print('j value is', j)

程序会输出:

  1. yield tmp:9
  2. j value is 9

可见代码会在上次yield 的地方,再次向下执行。

我们再次执行代码:

  1. k = next(t)
  2. print('k value is', k)

程序会输出:

  1. yield tmp:25
  2. k value is 25

t 中的元素被遍历完后,如果再次执行next(t),则会抛出StopIteration 异常。

使用next() 函数来遍历生成器中的所有元素是很麻烦的,我们可以像遍历列表一样,用for 循环来遍历生成器中的元素:

  1. for i in t:
  2. print(i)

输出如下:

  1. test...
  2. yield tmp:1
  3. 1
  4. yield tmp:9
  5. 9
  6. yield tmp:25
  7. 25

整个遍历过程中,字符串test... 只被输出了一次,并没有被输出三次。

说明当代码执行到yield 时,并没有从函数test() 中返回,代码只是暂停在了yield 处,等下次需要数据时,会接着从上次的yield 处接着执行。

生成器比列表节省内存

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

  1. >>> l = [i for i in range(10000)]
  2. >>> sys.getsizeof(l) # 内存占用 87624 字节
  3. 87624

sys 模块的getsizeof 方法可以查看一个对象的大小,单位是字节

用生成器来实现的话,是这样的:

  1. >>> l = (i for i in range(10000))
  2. >>> sys.getsizeof(l) # 内存占用 88 字节
  3. 88

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

5,强制类型转换

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

  1. >>> type('')
  2. <class 'str'>
  3. >>> type([])
  4. <class 'list'>
  5. >>> type(())
  6. <class 'tuple'>
  7. >>> type({})
  8. <class 'dict'>
  9. >>> type(set())
  10. <class 'set'>

每个类都有构造方法,这些构造方法可以将其它类型的数据,转换成该类型数据,我们也可以将这种转换称为强制类型转换

提示:

构造方法是一个的初始化方法,就是用什么样的数据去构造一个特定类的对象。

当介绍到类与对象时,我们会详细介绍。

str强制转换

作用: 将其它类型数据转换成字符串

原型: str(object='') -> str

参数: 任意类型数据

返回值: 字符串

示例:

  1. >>> str(1) # 将数字转换成字符串
  2. '1'
  3. >>> str([1, 2]) # 将列表转换成字符串
  4. '[1, 2]'
  5. >>> str((1, 2)) # 将元组转换成字符串
  6. '(1, 2)'

list强制转换

作用: 将一个可迭代类型转成列表

原型: list(iterable) -> list

参数: 任意可迭代类型数据

返回值: 列表

示例:

  1. >>> list((1, 2)) # 将一个元组转成列表
  2. [1, 2]
  3. >>> list(range(3)) # 将一个 range 对象转成列表
  4. [0, 1, 2]

tuple强制转换

作用: 将一个可迭代类型转成元组

原型: tuple(iterable) -> tuple

参数: 任意可迭代类型数据

返回值: 元组

示例:

  1. >>> tuple([1, 2]) # 将一个列表转成元组
  2. (1, 2)
  3. >>> tuple(range(3)) # 将一个 range 对象转成元组
  4. (0, 1, 2)

dict强制转换

作用: 将一个可迭代类型数据转成字典

原型: dict(iterable) -> dict

参数: iterable 是一个可迭代对象,并且该对象中的元素是元组

返回值: 字典

示例:

  1. >>> t = ((1, 2), (2, 3)) # t 是一个元组,其中的元素也是元组
  2. >>> dict(t)
  3. {1: 2, 2: 3}
  4. >>>
  5. >>> l = [(1, 2), (2, 3)] # l 是一个列表,其中的元素是元组
  6. >>> dict(l)
  7. {1: 2, 2: 3}

set强制转换

作用: 将一个可迭代类型数据转成集合

原型: set(iterable) -> set

参数: 一个可迭代对象

返回值: 集合

其实,我们在介绍集合时,都是用的这种方式来声明的集合,示例:

  1. >>> set('abc') # 将一个字符串转成集合
  2. {'b', 'c', 'a'}
  3. >>> set([0, 1]) # 将一个列表转成集合
  4. {0, 1}
  5. >>> set((0, 1)) # 将一个元组转成集合
  6. {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. unix 密码破解,zip破解总结

    unix /etc/passwd 破解,假设的前两位是salt import crypt #数据比较 def password_crak(pass_word): salt = pass_word[0: ...

  2. HTML、CSS与JS实现简易iPhone计算器

    效果如图 源码,通俗易懂 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...

  3. 实战| 配置DataDog监控Apache Hudi应用指标

    1. 可用性 在Hudi最新master分支,由Hudi活跃贡献者Raymond Xu贡献了DataDog监控Hudi应用指标,该功能将在0.6.0 版本发布,也感谢Raymond的投稿. 2. 简介 ...

  4. MyBatis(一) 概述与SQL定制、对象映射

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.MyBatis概述 1.mybatis简介 MyBatis 是支持定制化 SQL.存储过程以及高级映 ...

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

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

  6. Java实现 LeetCode 509 斐波那契数

    509. 斐波那契数 斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列.该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和.也就是: F(0) = 0, F(1) = 1 ...

  7. Java实现 LeetCode 507 完美数

    507. 完美数 对于一个 正整数,如果它和除了它自身以外的所有正因子之和相等,我们称它为"完美数". 给定一个 整数 n, 如果他是完美数,返回 True,否则返回 False ...

  8. Java实现最近点问题

    **问题描述:** 给定某空间中(直线空间或平面空间)n个点,请找出它们中的最近点对.你需要完成下列任务: 1.随机产生或手工输入n个点的坐标. 2.输出最近的两个点的坐标. 3.算法尽可能效率高. ...

  9. Linux链接命令及软链接、硬链接详解

    命令ln详解 命令ln,所在路径为: 可以看到,它的路径为:/usr/bin/ln,因此,它的执行权限是所有用户 命令的基本功能是创建链接文件(硬链接),例如:ln /etc/issue /tmp 选 ...

  10. Mybatis连接池及事务

    一:Mybatis连接池 我们在学习WEB技术的时候肯定接触过许多连接池,比如C3P0.dbcp.druid,但是我们今天说的mybatis中也有连接池技术,可是它采用的是自己内部实现了一个连接池技术 ...