19 多个装饰器的执行顺序 yield表达式形式 生成式 递归函数

叠加多个装饰器分析 yield表达式形式 生成式 递归函数

1 多个装饰器的执行顺序

函数外包裹函数的目的是为了向内部函数wrapper传参。
最终都是将原函数func_test换成wrapper函数。

装饰器的加载顺序从下到上。
装饰器的执行顺序从上到下。

# 3. func1指向的是原函数wrapper2的内存地址
def deco1(func1):
    print('deco1 start')
    def wrapper1(*args, **kwargs):
        print('wrapper1 start')
        res = func1()  # 4 func1是wrapper2
        print('wrapper1 stop')
        return res
    print('deco1 stop')
    return wrapper1
    
# 2. func2指向的是原函数wrapper3的内存地址
def deco2(func2):
    print('deco2 start')
    def wrapper2(*args, **kwargs):
        print('wrapper2 start')
        res = func2()  # 5 func2是wrapper3
        print('wrapper2 stop')
        return res
    print('deco2 stop')
    return wrapper2

# 1. func3指向的是原函数func_test的内存地址
def deco3(func3):  
    print('deco3 start')
    def wrapper3(*args, **kwargs):
        print('wrapper3 start')
        res = func3()  # 6 func3是原函数func_test
        print('wrapper3 stop')
        return res
    print('deco3 stop')
    return wrapper3

# 装饰器的加载顺序从下到上。
@deco1  
# func_test = deco1(func_test) 
# => func_test = deco1(wrapper2)  
# => func_test = wrapper1

@deco2  
# func_test = deco2(func_test) 
# => func_test = deco2(wrapper3)
# => func_test = wrapper2 

@deco3  
# func_test = deco3(func_test) 
# => func_test = wrapper3
def func_test():
    print('func_test')

# 装饰器的执行顺序从上到下。
func_test()
'''
deco3 start
deco3 stop
deco2 start
deco2 stop
deco1 start
deco1 stop
wrapper1 start
wrapper2 start
wrapper3 start
func_test
wrapper3 stop
wrapper2 stop
wrapper1 stop
'''

2 yield表达式形式

变量 = yield 返回值

函数内存在yield语句,调用这个函数不会执行代码,返回一个生成器。
通过生成器的next()方法触发函数体代码的运行,直到yield语句,返回yield后面的表达式。
再通过next或send方法触发函数体代码的运行,直到下一个yield语句,依此类推。
如果代码后面无yield语句,则抛出StopIteration异常。

def func(p1):
    print('开始执行。')
    while 1:
        p2 = yield '迭代结果'
        print(f'{p1} - {p2}')

gen = func(1)
# gen.send('测试') 报错,不能为一个新生成器传值

res1 = next(gen)  # 开始执行。
print(res1)  # 迭代结果

res2 = next(gen)  # 1 - None
print(res2)  # 迭代结果

res3 = gen.send(None)  # 1 - None
print(res3)  # 迭代结果

res4 = gen.send('2')  # 1 - 2
print(res4)  # 迭代结果

gen.close()
next(gen)  # 抛出异常 StopIteration
  1. 生成器的方法send主要用于向生成器对象传值。
    send()的参数会成为yield返回的值,可以将其赋值给yield等号左边的变量。
    yield后面的表达式会作为迭代器的本次迭代结果返回。
  2. 函数send只接受一个参数。
  3. gen.send(None) 等同于 next(gen)。
  4. gen.close()用于关闭一个迭代器,之后如果再调用next或send方法则会抛出StopIteration异常。

3 三元表达式 生成式

3.1 三元表达式

def func(x, y):
	if x > y:
		return x
	else:
		return y

三元代表三个要素:
判断条件,条件成立时的结果,条件不成立时的结果

条件成立时的结果 if 条件 else 条件不成立时的结果

def func(x, y):
	res = x if x > y else y
	return res

3.2 生成式

3.2.1 列表生成式

[表达式 for 元素 in 可迭代对象 if 条件]

lst = ['a', '123', 'cc22c']
new_lst = []
for each in lst:
	if each.isdigit():
	    new_lst.append(int(each))
print(new_lst)  # [123]
lst = ['a', 'bb', 'ccc']
new_lst = [int(each) for each in lst if each.isdigit()]
print(new_lst)  # [123]
3.2.2 字典生成式

{键 : 值 for 元素 in 可迭代对象 if 条件}

old_dict = dict(a=1, A=2, b=3, c=4, C=5)
print(old_dict)  # {'a': 1, 'A': 2, 'b': 3, 'c': 4, 'C': 5}
# 大小写的key值合并,统一以小写输出
new_dict = {each_key.lower() : old_dict.get(each_key.lower(), 0) + old_dict.get(each_key.upper(), 0) for each_key in old_dict}
print(new_dict)  # {'a': 3, 'b': 3, 'c': 9}
3.2.3 集合生成式

{表达式 for 元素 in 可迭代对象 if 条件}

3.2.4 生成器表达式

没有元组生成式

(表达式 for 元素 in 可迭代对象 if 条件)

得到生成器

gen = (i for i in range(10) if i < 2)
print(next(gen))  # 0
print(next(gen))  # 1
print(next(gen))  # 抛出异常StopIteration

应用 统计文件字符数

with open(r'./db.txt', mode='rt', encoding='utf-8') as f:
    total_num = sum(len(each_line) for each_line in f)
print(total_num)

生成器表达式得到的是生成器,属于可迭代对象。
sum(表达式 for 元素 in 可迭代对象 if 条件)
list(表达式 for 元素 in 可迭代对象 if 条件)

4 递归函数

4.1 什么是递归函数

也可以称为函数的递归调用,是函数嵌套调用的一种特殊形式。
指的是在在调用一个函数的过程中直接或间接地调用这个函数本身
直接调用自己

def func():
	func()

func()

间接调用自己

def func1():
	func2()
def func2():
	func1()
func1()

函数每调用一次都会产生自己的局部空间。
如果允许无限地递归调用,则会无限地申请内存空间,这样会耗尽可用内存空间。python解释器对递归调用深度进行了限制,默认是1000层。

sys.getrecursionlimit()  # 1000
sys.setrecursionlimit(2000)  # 设置为2000层
4.2 为什么使用递归函数

递归的本质是循环,使用目的是重复执行一段代码。
将一段代码循环运行的方案

while 1:
	代码
def func():
	代码
	func()
func()

递归调用不应该无限地进行下去,需要在满足一定条件后结束调用。
使用return语句来结束调用。

4.3 递归调用的两个阶段

回溯阶段递推阶段
递归调用中,逐层深入调用自己的阶段称为回溯阶段。
在满足一定条件后函数在某一层调用过程中会结束递归调用,从那一层开始逐层向外返回的阶段称为递推阶段。

有关列表的应用

lst = [1, 2, [3, 4, [5, [6], 7]], 8, 9]
def print_elem(lst):
    for elem in lst:
        if type(elem) is list:
            print_elem(elem)
        else:
            print(elem)

print_elem(lst)

5 练习

5.1

文件内容如下
egon male 18 3000
alex male 38 30000
wupeiqi female 28 20000
yuanhao female 28 10000
要求:

  1. 从文件中取出每一条记录放入列表中,
    列表的每个元素都是{‘name’:‘egon’,‘sex’:‘male’,‘age’:18,‘salary’:3000}的形式;
  2. 计算所有人的薪资之和;
  3. 取出所有的男人的名字;
  4. 将每个人的信息中的名字映射成首字母大写的形式;
  5. 过滤掉名字以a开头的人的信息。
with open(r'./test.txt', mode='rt', encoding='utf-8') as f:
    # value_lst = [each_line.strip().split(' ') for each_line in f]
    key_lst = ['name', 'sex', 'age', 'salary']
    user_lst = [{
        key_lst[0]: each_list[0],
        key_lst[1]: each_list[1],
        key_lst[2]: each_list[2],
        key_lst[3]: each_list[3]
    } for each_list in
        [each_line.strip().split(' ') for each_line in f]
    ]
print(user_lst)
# 计算所有人的薪资之和
salary_sum = sum(int(each_dict['salary']) for each_dict in user_lst)
print(salary_sum)

# 取出所有的男人的名字
male_name_lst = [each_dict['name'] for each_dict in user_lst if each_dict['sex'] == 'male']
print(male_name_lst)

# 将每个人的信息中的名字映射成首字母大写的形式 captalize
capitalize_name_lst = [each_dict['name'].capitalize() for each_dict in user_lst]
print(capitalize_name_lst)

# 过滤掉名字以a开头的人的信息 startswith
target_name_lst = [each_dict['name'] for each_dict in user_lst if not each_dict['name'].startswith('a')]
print(target_name_lst)
5.2 斐波那契数列

使用递归打印斐波那契数列,即数列中一个数是前两个数的和。

def get_fib_num(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return get_fib_num(n - 1) + get_fib_num(n - 2)

for i in range(10):
    print(get_fib_num(i), end=' ')
5.3

一个嵌套很多层的列表,如 l=1,2,[3,[4,5,6,[7,8,[9,10,[11,12,13,[14,15]]]]]]],用递归取出所有的值。

l = [1, 2, [3, [4, 5, 6, [7, 8, [9, 10, [11, 12, 13, [14, 15]]]]]]]
def print_elem(l):
    for each_elem in l:
        if type(each_elem) is list:
            print_elem(each_elem)
        else:
            print(each_elem, end=' ')

print_elem(l)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值