匿名函数(lambda)
lambda可以定义一个匿名函数,匿名函数就是没有函数名的函数。像我们用def定义的函数都有函数名,而用lambda定义的函数就不需要函数名,只要有函数中的运算逻辑就可以。lambda定义匿名函数时只能有一行逻辑,所以lambda定义的匿名函数通常是一个表达式,就像C++中的宏。但是lambda也能定义复杂逻辑的匿名函数,我们只需在表达式中放入一个复杂函数就可以了。lambda常跟高阶函数map和filter联合使用。
基本结构
lambda 形参1, 形参2, ..., 形参n: 运算逻辑表达式
lambda后面直接写形参名,不用写函数名。形参写完后直接用冒号,在冒号后定义运算逻辑表达式,必须在这一行把表达式写完,不能换行但可以用\分成多行。所以lambda和def的区别在于,def后面要定义函数名,形参要放到括号中,def定义的函数可以有多行运算逻辑表达式。
anonymous = lambda a, b: a + b # 使用lambda定义一个匿名函数,并赋值给变量anonymous
print(anonymous(1, 1)) # 执行 1 + 1
print(anonymous(5, 1)) # 执行 5 + 1
执行结果如下:
所以 lambda a, b: a + b 就相当于如下函数:
def add(a, b):
return a + b
anonymous = add
print(anonymous(1, 1)) # 执行 1 + 1
print(anonymous(5, 1)) # 执行 5 + 1
我们还可以在lambda中写一些其他的表达式,例如用来处理字符串,把每一个字符串的首字母大写。
anonymous = lambda x: x.capitalize()
print(anonymous('hello'))
print(anonymous('world'))
执行结果如下:
延迟执行函数
在lambda的逻辑表达式中放入执行的函数,可以让本该执行的函数延迟执行。就相当于在被执行的函数外又套了一层函数,外层函数未执行时,内层函数不能执行。
def people_info(name, sex, age):
"""
返回对应的人物信息
:param name: 姓名
:param sex: 性别
:param age: 年龄
:return: 人物信息
"""
print('开始执行people_info函数')
if sex not in ['男', '女']:
return '性别输入错误,请输入正确的性别男或者女'
adult = {'男': '先生', '女': '女士'}
minor = {'男': '小弟弟', '女': '小妹妹'}
if age >= 18:
return f'{name}{adult[sex]}今年{age}岁'
else:
return f'{name}{minor[sex]}今年{age}岁'
anonymous = lambda: people_info('小明', '男', 23)
print('开始执行匿名函数')
print(anonymous())
执行结果如下:
从执行结果中我们可以看出,需要先执行匿名函数,才会执行people_info函数。这就类似一个闭包函数,只要外层的匿名函数未执行时,内部的people_info函数也不会执行。通过这种方式,我们可以把一个执行函数变成一个待执行函数。在一些需要绑定执行函数的触发事件中可以应用,也可以用来简化一些闭包函数。
内置高阶函数
map()
map函数接收两个参数,第一个参数为函数,第二个参数为可迭代对象。map会返回一个迭代器,这个迭代器能把传入的函数依次作用于可迭代对象的每一个元素。我们可以使用next函数让生成器逐次执行,调用依次next函数迭代器就会把函数作用于一个元素,直到所有的元素都被作用完。现在我们不懂迭代器,不懂next函数没关系,我们知道for循环会自动使用next函数,我们用for循环就可以了。
def add_postfix(name: str):
"""
给文件添加后缀
:param name: 文件名
:return:
"""
return name + '.txt'
novel_list = ['百练成仙', '斗破苍穹', '求魔', '遮天', '凡人修仙传']
for i in map(add_postfix, novel_list):
print(i)
执行结果如下:
我们可以看到列表novel_list中的每一个元素都被add_postfix函数处理过了,每个小说都加上了后缀.txt。
list函数可以把迭代器变成列表,所以我们也可以用list函数处理map函数。
def add_postfix(name: str):
"""
给文件添加后缀
:param name: 文件名
:return:
"""
return name + '.txt'
novel_list = ['百练成仙', '斗破苍穹', '求魔', '遮天', '凡人修仙传']
novel_list = list(map(add_postfix, novel_list))
print(novel_list)
执行结果如下:
联合lambda
像给文件加后缀这种简单的逻辑,使用lambda会更简单,让代码变短。
novel_list = ['百练成仙', '斗破苍穹', '求魔', '遮天', '凡人修仙传']
novel_list = list(map(lambda name: name + '.txt', novel_list))
print(novel_list)
执行结果如下:
filter()
filter函数接收两个参数,第一个参数为函数,第二个参数为可迭代对象。filter会返回一个迭代器,这个迭代器能把传入的函数依次作用于可迭代对象的每一个元素。但于map不同的是,filter会根据函数返回值的真假做出筛选,只留下返回值为真的元素。我们可以使用next函数让迭代器逐次执行,调用依次next函数生成器就会把函数作用于一个元素,直到所有的元素都被作用完。跟map函数一样我们用for循环就可以了。
def judge_odd(number: int):
"""
判断奇数
:param number: 整数
:return: bool
"""
if number % 2 > 0:
return True
return False
number_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for i in filter(judge_odd, number_list):
print(i)
执行结果如下:
从执行结果中我们可以看到所有的奇数都被留下来了,而偶数就被筛掉了。
list函数可以把迭代器变成列表,所以我们也可以用list函数处理filter函数。
def judge_odd(number: int):
"""
判断奇数
:param number: 整数
:return: bool
"""
if number % 2 > 0:
return True
return False
number_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
number_list = list(filter(judge_odd, number_list))
print(number_list)
执行结果如下:
联合lambda
像筛选奇数这种简单的逻辑,直接使用lambda更简单。
number_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
number_list = list(filter(lambda x: x % 2 > 0, number_list))
print(number_list)
执行结果如下:
三目运算符(if else)
变量 = 对象1 if 条件 else 对象2
写作一行的if else语句可以作为一种运算符,叫三目运算符,它的运算逻辑就跟if else的逻辑一模一样。当满足if后面的条件时,变量=对象1;当不满足if后面的条件时,变量=对象2。
name = "爆笑蛙" if 2 > 1 else "小明"
print(name)
因为2 > 1条件为真,所以name的值为'爆笑蛙'。执行结果如下:
你还可以把条件改为2 < 1看name的值是不是'小明'。
生成式
python中有3个生成式:列表生成式、集合生成式、字典生成式。它们能有效简化我们的代码,把需要多行代码表示的语句变成一行语句。
列表生成式
list1 = [表达式 for循环语句 if条件语句]
列表生成式可以按照某种逻辑生成一个列表,通过for循环不断输出值,然后把值给表达式运算,再把运算结果给if条件语句判断是否要把运算结果留在列表中。if条件语句不是必要的,当不需要条件判断时可以省略if语句。表达式就是一段运算逻辑,可以只是一个变量、一个lambda匿名函数、直接调用其他函数、使用各种运算符的运算逻辑。
单层for循环
for循环语句中没有嵌套for循环时,逻辑比较简单易懂,适合我们初步了解列表生成式。
list1 = [i for i in range(10)]
print(list1)
执行结果如下:
从执行结果中我们可以发现,列表生成式把所有for循环迭代出来的值都放到了列表中。相当于下面这段代码:
list1 = []
for i in range(10):
list1.append(i)
print(list1)
这种方式需要3行代码才能做到,但列表生成式一行搞定。
多层for循环
for循环中嵌套了一层或多层for循环,多层for循环写在一行,需要一些逻辑思维才能弄懂。
surname = ['赵', '钱', '孙', '李']
name = ['三', '四', '五']
list1 = [i + n for i in surname for n in name]
print(list1)
执行结果如下:
从执行结果中我们可以看到,第一个for循环是外层for循环,第二个for循环是内层for循环。for循环的嵌套可以一直写下去,最后一个for循环为最内层for循环。相当于下面这段代码:
surname = ['赵', '钱', '孙', '李']
name = ['三', '四', '五']
list1 = []
for i in surname:
for n in name:
list1.append(i + n)
print(list1)
这种方式需要6行代码才能做到,列表生成式3行搞定。
单层if条件
在for循环后面,我们可以写一个if判断语句来控制那些结果会被放到列表中。
list1 = [i for i in range(10) if i % 2 > 0]
print(list1)
执行结果如下:
从执行结果中我们可以发现,只有i满足if后面的条件时,i才会被放到列表中,所以列表中全是奇数。相当于下面这段代码:
list1 = []
for i in range(10):
if i % 2 > 0:
list1.append(i)
print(list1)
这种方式需要4行代码才能做到,列表生成式一行搞定。
联合三目运算符
在表达式中使用三目运算符,可以增加更多的选择。
list1 = [i if i > 5 else 1 for i in range(10)]
print(list1)
执行结果如下:
通过三目运算符,我们可以改变某些结果的值。相当于下面这段代码:
list1 = []
for i in range(10):
if i > 5:
list1.append(i)
else:
list1.append(1)
print(list1)
这种方式需要6行代码才能做到,列表生成式一行就搞定。
集合生成式
set1 = {表达式 for循环语句 if条件语句}
集合生成式可以按照某种逻辑生成一个集合,通过for循环不断输出值,然后把值给表达式运算,再把运算结果给if条件语句判断是否要把运算结果留在集合中。if条件语句不是必要的,当不需要条件判断时可以省略if语句。表达式就是一段运算逻辑,可以只是一个变量、一个lambda匿名函数、直接调用其他函数、使用各种运算符的运算逻辑。
单层for循环
for循环语句中没有嵌套for循环时,逻辑比较简单易懂,适合我们初步了解集合生成式。
set1 = {i for i in 'abcdefghij'}
print(set1)
执行结果如下:
从执行结果中我们可以看到,集合生成式把for循环迭代出来的值都放到了集合中。相当于下面这段代码:
set1 = set()
for i in 'abcdefghij':
set1.add(i)
print(set1)
这种方式需要3行代码才能做到,集合生成式一行搞定。
多层for循环
for循环中嵌套了一层或多层for循环,多层for循环写在一行,需要一些逻辑思维才能弄懂。
set1 = {i.upper() + n for i in 'abc' for n in 'uvw'}
print(set1)
执行结果如下:
从执行结果中我们可以看到,第一个for循环是外层for循环,第二个for循环是内层for循环。for循环的嵌套可以一直写下去,最后一个for循环为最内层for循环。相当于下面这段代码:
set1 = set()
for i in 'abc':
for n in 'uvw':
set1.add(i.upper() + n)
print(set1)
这种方式需要4行代码才能做到,集合生成式一行搞定。
加入if条件语句
在for循环后面,我们可以写一个if判断语句来控制那些结果会被放到集合中。
set1 = {i for i in 'abcdefghij' if i > 'e'}
print(set1)
执行结果如下:
从执行结果中我们可以发现,只有i满足if后面的条件时,i才会被放到集合中,所以集合中全是大于'e'的字符串。相当于下面这段代码:
set1 = set()
for i in 'abcdefghij':
if i > 'e':
set1.add(i)
print(set1)
这种方式需要4行代码才能做到,集合生成式一行搞定。
联合三目运算符
在表达式中使用三目运算符,可以增加更多的选择。
set1 = {i if i > 'e' else i.upper() for i in 'abcdefghij'}
print(set1)
执行结果如下:
通过三目运算符,我们可以改变某些结果的值。相当于下面这段代码:
set1 = set()
for i in 'abcdefghij':
if i > 'e':
set1.add(i)
else:
set1.add(i.upper())
print(set1)
这种方式需要6行代码才能做到,集合生成式一行就搞定。
字典生成式
dict1 = {得到键值对的表达式 for循环语句 if条件语句}
字典生成式可以按照某种逻辑生成一个字典,通过for循环不断输出值,然后把值给表达式运算,再把运算结果给if条件语句判断是否要把运算结果留在字典中。if条件语句不是必要的,当不需要条件判断时可以省略if语句。表达式就是一段运算逻辑,可以只是一个变量、一个lambda匿名函数、直接调用其他函数、使用各种运算符的运算逻辑。
单层for循环
for循环语句中没有嵌套for循环时,逻辑比较简单易懂,适合我们初步了解字典生成式。
dict1 = {key: value for key, value in [['数学', 99], ['语文', 89], ['英语', 85]]}
print(dict1)
执行结果如下:
从执行结果中我们可以看到,字典生成式把for循环迭代出来的值都放到了字典中。相当于下面这段代码:
dict1 = {}
for key, value in [['数学', 99], ['语文', 89], ['英语', 85]]:
dict1[key] = value
print(dict1)
这种方式需要3行代码才能做到,字典生成式一行搞定。
多层for循环
for循环中嵌套了一层或多层for循环,多层for循环写在一行,需要一些逻辑思维才能弄懂。
dict1 = {f'{i}_{n}': n for i in 'abc' for n in range(1, 3)}
print(dict1)
执行结果如下:
从执行结果中我们可以看到,第一个for循环是外层for循环,第二个for循环是内层for循环。for循环的嵌套可以一直写下去,最后一个for循环为最内层for循环。相当于下面这段代码:
dict1 = {}
for i in 'abc':
for n in range(1, 3):
dict1[f'{i}_{n}'] = n
print(dict1)
这种方式需要4行代码才能做到,字典生成式一行搞定。
加入if条件语句
在for循环后面,我们可以写一个if判断语句来控制那些结果会被放到字典中。
dict1 = {key: value for key, value in [['数学', 99], ['语文', 89], ['英语', 85]] if value > 90}
print(dict1)
执行结果如下:
从执行结果中我们可以看到,只有value满足if条件时,key: value才会被放到字典中,所以字典中只放了数学的成绩。相当于下面这段代码:
dict1 = {}
for key, value in [['数学', 99], ['语文', 89], ['英语', 85]]:
if value > 90:
dict1[key] = value
print(dict1)
这种方式需要4行代码才能做到,字典生成式一行搞定。
联合三目运算符
在表达式中使用三目运算符,可以增加更多的选择。
dict1 = {key: value if value < 90 else '优秀' for key, value in [['数学', 99], ['语文', 89], ['英语', 85]]}
print(dict1)
执行结果如下:
通过三目运算符,我们可以改变某些结果的值。相当于下面这段代码:
dict1 = {}
for key, value in [['数学', 99], ['语文', 89], ['英语', 85]]:
if value < 90:
dict1[key] = value
else:
dict1[key] = '优秀'
print(dict1)
这种方式需要6行代码才能做到,集合生成式一行就搞定。