三元表达式和匿名函数
一 三元表达式
语法: 条件为真返回的值 if 条件 else 条件为假返回的值
def get_max1(a, b):
if a > b:
return a
else:
return b
def get_max2(a, b):
return a if a > b else b
print(get_max1(1, 2)) # 2
print(get_max2(1, 2)) # 2
上面两个函数实现的功能是完全一样的,下面使用的就是三元表达式,可以看出,代码更加的简洁,而且可读性也不会变差。
二 多种生成式
2.1 列表生成式
语法:[表达式 for 变量名 in 可迭代对象 if 条件 ] if可加可不加
# 需求:生成一个1到10中2的倍数的列表
res = [i for i in range(2, 11, 2)]
print(res) # [2, 4, 6, 8, 10]
res1 = [x * y for x in [1, 2, 3] for y in [4, 5, 6]] # 相当于循环嵌套
print(res1) # [4, 5, 6, 8, 10, 12, 12, 15, 18]
my_list = ['jasper', 'jack', 'jason']
# 需求:给my_list的每个数据都加上_NB
# 方式一:
new_list = []
for i in my_list:
# new_list.append(i + '_NB')
new_list.append(''.join([i, '_NB']))
print(new_list) # ['jasper_NB', 'jack_NB', 'jason_NB']
# 方式二:用列表生成式
new_list1 = [''.join([i, '_NB']) for i in my_list]
print(new_list1) # ['jasper_NB', 'jack_NB', 'jason_NB']
new_list2 = [''.join([i, '_NB']) for i in my_list if i != 'jasper']
print(new_list2) # ['jack_NB', 'jason_NB']
# 支持if判断 for循环出来的数据 先进行判断 条件成立则交给左边的表达式 条件不成立则不交给表达式
列表生成式可以包含for和if,但是不包含其他的。
2.2 字典生成式
语法:{k:v for k in 可迭代对象 for v in 可迭代对象}
# 字典生成式
res = {k: v for k in range(3) for v in ['jasper', 'lili', 'jack']}
print(res) # {0: 'jack', 1: 'jack', 2: 'jack'}
my_dict = {'name': 'jasper', 'age': 18, 'hobby': 'read'}
# 需求:将字典里的k,v互换
new_dict = {v: k for k, v in my_dict.items()}
print(new_dict) # {'jasper': 'name', 18: 'age', 'read': 'hobby'}
2.3 集合生成式
语法:{表达式 for 变量名 in 可迭代对象} 可以加if条件判断,集合里for循环的数据必须是不可变类型。
# 集合生成式
my_set = {i for i in range(10) if i != 4}
print(my_set, type(my_set)) # {0, 1, 2, 3, 5, 6, 7, 8, 9} <class 'set'>
python中没有元组生成式
nt_know = (i for i in range(5))
print(my_dont_know) # <generator object <genexpr> at 0x0000014ABFFA07B0>
# 是一个生成器对象
三 匿名函数
3.1 简介
匿名函数就是没有函数名的函数,它主要用在需要一个函数,但实现的功能很简单,而且只需要使用一次,这时就可以使用匿名函数。
3.2 语法
关键字lambda 形参: 返回值
# 匿名函数
lambda a, b: a * b
# 调用方式一:
# 将整个匿名函数括起来后面直接加括号调用
res = (lambda a, b: a * b)(3, 4)
print(res) # 12
# 调用方式二:
# 将匿名函数赋值给一个变量名使用变量名加括号调用
func = lambda a, b: a * b
print(func(3, 4)) # 12
说明:使用lambda表达式时,可以有多个参数,之间用逗号隔开,表达式只能有一个,只能返回一个值,不支持for和while等。
3.3 实际应用
# # 匿名函数
# lambda a, b: a * b
#
# # 调用方式一:
# # 将整个匿名函数括起来后面直接加括号调用
res = (lambda a, b: a * b)(3, 4)
print(res) # 12
#
# # 调用方式二:
# # 将匿名函数赋值给一个变量名使用变量名加括号调用
func = lambda a, b: a * b
print(func(3, 4)) # 12
# 需求:编写一个计算圆的面积的函数
import math
def get_area(r):
return math.pi * r ** 2
print(get_area(3)) # 28.274333882308138
# 使用匿名函数
print((lambda r: math.pi * r ** 2)(3)) # 28.274333882308138
匿名函数一般和内置函数结合使用,可以减少代码的书写量。
# 匿名函数和内置函数结合使用
my_dict = {
'fish': 100,
'pig': 200,
'beef': 300
}
# 求字典中value的最大值
res1 = max(my_dict)
print(res1) # pig 找到的是字典中最大的key
res2 = max(my_dict, key=lambda k: my_dict.get(k))
print(res2) # beef
四 内置函数
4.1 重要内置函数
max()
求最大值
max函数如果只提供了一个位置参数,必须是一个非空的可迭代对象,返回可迭代对象中最大的元素,如果提供两个或两个以上的位置参数,则返回最大的位置参数。
# max(iterable, *[, default=obj, key=func]) -> value
# max(arg1, arg2, *args, *[, key=func]) -> value
print(max([i for i in range(4)])) # 3
print(max(3, 5, 7, 9, 2)) # 9
print(max('j', 'z', 'A')) # z
min()
求最小值
和max函数相反
# min(iterable, *[, default=obj, key=func]) -> value
# min(arg1, arg2, *args, *[, key=func]) -> value
print(min([i for i in range(4)])) # 0
print(min(3, 5, 7, 9, 2)) # 2
print(min('j', 'z', 'A')) # A
map()
映射
第一个参数传一个函数,可以是内置的也可以是自定义的,后面可以传多个可迭代对象,返回一个迭代器对象,可用list()转换。
这个函数的意思就是将可迭代对象里的每个元素应用到函数中
list1 = [1, 'name', 3, 4]
tuple1 = (6, 7, 8, 9)
str1 = 'hello'
print(map(str, list1)) # <map object at 0x0000018D6C5D5FA0>
print(list(map(str, list1))) # ['1', 'name', '3', '4']
print(list(map(str, tuple1))) # ['1', 'name', '3', '4']
print(list(map(str, str1))) # ['h', 'e', 'l', 'l', 'o']
# 将可迭代对象的每个数据都转成字符串
# 使用自定义参数
def func(x, y, z):
return x, y, z
list2 = [1, 2, 3]
list3 = [4, 5, 6]
list4 = [4, 5, 6, 7, 8, 9]
print(list(map(func, list2, list3, list4))) # [(1, 4, 4), (2, 5, 5), (3, 6, 6)]
# 如果长度不一致 结果取决于最短的那个
filter()
过滤
用于过滤序列,过滤掉不符合条件的数据,返回一个迭代器对象,可用list()转换。
两个参数,参数1是函数,参数2是序列,将序列里的每一个元素作为参数传入函数进行判断,返回True或False,
将结果为True的放到新的列表中。
l1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 去除掉l1的所有奇数
def func(n):
return n % 2 == 0
print(list(filter(func, l1))) # [2, 4, 6, 8]
# 使用匿名函数
res = filter(lambda n: n % 2 == 0, l1)
print(list(res)) # [2, 4, 6, 8]
reduce()
求和
reduce在python2中是一个内置函数,但是在python3中被移植到functools模块中。
两个参数:第1个是函数名,第二个是队列。
reduce函数先从队列或列表中取出两个元素,执行函数,得到的结果作为一个元素,在从左至右依次取出一个元素,执行函数,直到队列所有的元素被取完。返回的是一个数据值
from functools import reduce
l2 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 求列表中所有数的和
# 方式一
print(sum(l2)) # 45
# 方式二
print(reduce(lambda x, y: x + y, l2)) # 45
zip()
拉链
可以接受多个可迭代对象,然后将每个可迭代对象的第n个元素结合在一起,返回一个元组类型的迭代器,可用list()转换。
l1 = [1, 2, 3, 4]
dic = {
'name': 'jasper',
'age': 19,
'gander': 'male',
'hobby': 'read',
}
str1 = 'jack'
print(list(zip(l1, dic, str1)))
# # [(1, 'name', 'j'), (2, 'age', 'a'), (3, 'gander', 'c'), (4, 'hobby', 'k')]
如果长度不统一,决定结果的还是最短的那个。
4.2 常见内置函数
4.2.1 数据类型
# 数据类型相关
int()
float()
str()
list()
dict()
tuple()
bool()
set()
complex() # 复数
4.2.2 进制转换
# 进制转换
print(bin(100)) # 0b1100100 十转二
print(oct(100)) # 0o144 十转八
print(hex(100)) # 0x64 十转十六
int() # 其他进制转十进制
4.2.3 数学运算
# 数学运算
print(abs(-6)) # 6 求绝对值
print(pow(2, 3, 3)) # 2**3 % 3 a的b幂次方在和c取余
print(divmod(66, 3)) # (22, 0) 返回商和余数
print(round(99.6)) # 100 返回四舍五入
sum() # 求和
max() # 求最大
min() # 求最小
4.2.4 和作用域有关
# 和作用域有关
print(globals()) # 查看全局名称空间的名字
print(locals()) # 要在局部空间使用 此时结果和全局一致
4.2.5 输入输出
# 输入输出
input()
print()
4.2.6 文件相关
# 文件相关
open()
4.2.7 其他
all() # 所有未True才返回True
any() # 有一个未True就返回True
bytes('你', encoding='utf8') # b'\xe4\xbd\xa0' 将字符串转为二进制
callable() # 用于检查一个对象是否可调用
chr()
ord() # 根据ASC表实现数字和字符之间的转换
dir() # 查看内置属性
enumerate({1, 2, 3, 4})
# <enumerate object at 0x000001C183873540> [(0, 1), (1, 2), (2, 3), (3, 4)] 获取集合的枚举对象
evar()
exec() # 能够识别字符串中的代码并执行
format() # 格式化
help() # 打印帮助信息
hash() # 获取对象的哈希值
id() # 查看内存地址
isinstance(1, int) # True 判断数据类型 返回布尔值
len() # 返回一个对象中元素个数
reversed([1, 2, 3, 4, 5]) # reversed([1, 2, 3, 4, 5])
# 将一个序列反转 返回一个迭代器
range() # 生成数据
sorted() # 对可迭代对象进行排序
type() # 判断数据类型
练习
多层装饰器及有参装饰器的执行流程用文字具体描述出来
- 多层装饰器
函数test上面叠加了三个装饰器,从下至上依次是outer1,outer2,outer3,执行流程是,先将函数名test传入outer1的形参func_name1,此时func_name1是真正的test,返回inner1。将inner1传入中间的装饰器outer2,此时outer2中func_name2是inner1,返回inner2。将inner2传入最上面的装饰器outer3,此时outer3中的func_name3是inner2,返回inner3。因为outer3是最后一个装饰器,所以将inner3赋值给全局的变量名test,此时全局的test已经不是被装饰之前的test,而是inner3的内存地址,test(),调用test。其实是执行inner3,inner3中的func_name3为inner2,接着执行inner2,此时func_name2为inner1,接着执行inner1,而inner1才是真正的test,执行真正的test,return,接着inner2,inner3也依次结束。 - 有参装饰器
装饰器内部需要一个参数用于当作条件或者数据值,此时就需要给函数体传参。给函数体传参的方式有两种,第一种通过形参传入,但装饰器外层函数的形参是用来接收被装饰对象的,内层函数的形参是用来接收被装饰对象的参数的,都不能修改,所以只能用闭包函数传参,定义一个函数将装饰器包起来,形参中可传多个参数,在原装饰器同层返回原装饰器名,此时有参装饰器就完成了。执行流程是,被装饰对象上有一个@外层函数(参数),函数名加括号先执行外层函数,流程为将参数传入外层函数,定义一个原装饰器函数名放到外层函数的局部空间,返回原装饰器函数名,此时就变形为@原装饰器函数名,执行流程就和无参装饰器一致,此时函数体内部就可以访问到添加的参数。