在前面的课程中,我们已经学习了循环和函数的基本操作,这节内容主要针对循环和函数在项目使用过程中的一些更加有使用价值的操作进行分析和讲解
本节内容:
-
循环部分
- 列表构建器
- 列表动态构建器
- 循环操作序列对象
- 循环迭代遍历数据
-
函数部分
- 函数递归
- 参数使用函数
- 函数中返回函数
- 匿名函数
- 偏函数
1. 循环操作
1.1 列表构建器
常规情况下,我们定义列表的语法如下
lix = ["列表元素列表"]
如果在某些情况下,我们要定义一个1~100的列表,是一件特别麻烦的事情,手工编码就会变得非常的繁琐,此时,我们可以使用第一种方式来进行列表的构建
lix = list(range(1, 101))
执行结果:lix = [1, 2, 3, 4, 5, 6, ......]
但是,此时如果我们想要的不是自然数,而是每个数字的平方呢?
我们可以这么做
lix = [];
for x in range(1, 101):
lix.push(x ** 2)
执行结果:lix = [1,4,9,16,25.....]
但是通过这样的方式循环迭代比较繁琐,可以通过列表构建器来直接实现
lix = [x * x for x in range(1, 101)]
执行结果:lix = [1,4,9,16,25.....]
# 其实列表构建器中,就是一个简单的表达式操作
同样的,在列表构建器的表达式中,可以添加简单的条件处理
lix = [x * x for x in range(1, 101) if x % 2 == 0]
执行结果:lix = [4,16,36.....]
也可以在循环过程中,来使用多层循环嵌套,实现更加复杂的效果
lix = [x + y for x in "abc" for y in "xyz"]
执行结果:['ax', 'ay', 'az', 'bx', 'by', 'bz', 'cx', 'cy', 'cz']
1.2 列表动态构建器
但是我们通过前面的学习已经知道,这些数据都是加载到内存中的,如果列表中的数据量比较大的情况下,内存消耗是比较严重的
在某些情况下,我们只需要使用列表中的一部分数据,后面的数据并不是特别关心,如:通过列表来记录一个符合某种规则的序列,每次我们只是关心下一个数据,并不关心后面的N条数据,应该怎么做呢?比如我们需要一个奇数列表
# 常规构建器的做法
lix = [2*x + 1 for x in range(1, 101)]
# 执行结果:[1,3,5,7,9,11,13,15,17.....]
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
# 常规构建器可以直接构建生成
# 但是存在问题,如果一次构建的数据量太大,会严重占用内存
# 我们在使用该列表的时候,有可能只是使用前10项
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
# 使用列表动态构建器
lix = (2 * x - 1 for x in range(1, 101))
# 执行结果:print (lix) --> <generator object <genexpr> at 0x7f232e462048>
next(lix)
# 执行结果:1
next(lix)
# 执行结果:3
next(lix)
# 执行结果:5
next(lix)
# 执行结果:7
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
# 列表动态构建器
# 和构建器基本没有区别,创建的时候列表中是没有数据的
# 必须通过next()函数来获取列表中的下一条数据
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1.3. 循环列表
常规循环列表的方式
lix = ["远古巫灵泽拉斯", "机械先驱维克托", "惩戒之箭维鲁斯", "龙血武姬希瓦娜"]
for x in lix:
print(x)
执行结果:
远古巫灵泽拉斯
机械先驱维克托
惩戒之箭维鲁斯
龙血武姬希瓦娜
如果此时,我想象其他语言一样,在循环过程中操作当前正在循环的元素的下标呢?
可以通过enumerate()函数对列表进行处理
lix = ["远古巫灵泽拉斯", "机械先驱维克托", "惩戒之箭维鲁斯", "龙血武姬希瓦娜"]
for index, item in enumerate(lix):
print(index, item)
执行结果:
0 远古巫灵泽拉斯
1 机械先驱维克托
2 惩戒之箭维鲁斯
3 龙血武姬希瓦娜
1.4. 循环字典
因为列表、元组、集合中存储的都是一个个独立的元素,对列表的循环比较简单
那么如果循环key:value键值对的字典应该怎么做呢
我们回顾一下字典中常用的一些函数
dict.items();返回字典中的每一组key:value数据
dict.keys();返回字典中的所有的key组成的集合
dict.values();返回字典中所有的value组成的列表
lid = {"远古巫灵":"泽拉斯", "机械先驱":"维克托", "惩戒之箭":"维鲁斯", "龙血武姬":"希瓦娜"}
# 通过keys()循环遍历字典的key
for k in lid.keys():
print(k)
# 通过values()循环遍历字典的value
for v in lid.values():
print(v)
# 通过items()循环遍历所有的字典数据
for k, v in lid.items():
print(k, v)
1.5. 循环判断
最后我们需要补充一个非常重要的东西,通常情况,我们对于python中的序列对象可以进行循环处理,那么首先需要判断一下我们要处理的数据是不是循环,如果不是循环就会出现错误
# 循环字符串
s1 = "abc"
for x in s1:
print(x)
# 执行结果
~a
~b
~c
# 循环整数
s2 = 100;
for x in s2:
print(x)
# 执行结果:出现报错提示int对象不是iterable
~Traceback (most recent call last):
~File "<stdin>", line 1, in <module>
~TypeError: 'int' object is not iterable
我们看到,对于非序列对象,出现对象不是iterable的错误提示
iterable是Python中的迭代对象,序列对象一般都是迭代对象
那怎么判断一个对象是否迭代对象呢?
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
# 判断一个对象是否iterable迭代对象
# 首先通过from collections import Iterable语句来在当前
# python文件中引入collections模块中的Iterable类型
# 然后通过isinstance来判断我们要循环的对象是否Iterable对象
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
s1 = "abc",
s2 = [1,2,3,4]
s3 = (1,2,3,4)
s4 = {1,2,3,4}
s5 = {"1":"a", "2":"b", "3":"c"}
s6 = 100
执行结果
>>> isinstance(s1, Iterable)
True
>>> isinstance(s2, Iterable)
True
>>> isinstance(s3, Iterable)
True
>>> isinstance(s4, Iterable)
True
>>> isinstance(s5, Iterable)
True
>>> isinstance(s6, Iterable)
False
那这样就好办了,如果我们要遍历指定的数据,首先判断是否是迭代对象,是迭代对象我们再进行迭代操作就可以了
# 导入collections模块中的Iterable对象
from collections import Iterable
# 遍历数据
s1 = [1,2,3,4]
if isinstance(s1, Iterable):
for x in s1:
print(x)
s2 = 10000
if isinstance(s2, Iterable):
for x in s2:
print(x)
# 执行结果不会出现报错了
本节内容主要讲解了实际项目中经常用到的序列对象列表的高级使用方式,以及使用for循环进行序列对象循环遍历过程中的几种特殊的使用方式。下节内容,我们继续说另一个学过的东东~函数的高级操作方式。