进入python的世界_day13_python基础——函数之有参装饰器、装饰器修复、递归函数
写在开头:最近几天的知识很抽象,牢记以下几点
1.走到哪一步就看哪一步,碰到一个函数,如果没执行调用,就看成一行代码,函数体代码没执行调用可以先不看
2.作用域关系是在函数定义阶段就确定好了的,全局绑一个变量名局部都可以用
3.碰到名字+括号,在该域中先运行
一、叠加多层语法糖 ——用结论去找答案
结论:
叠加多个装饰器语法糖
- 加载顺序(outter函数的调用顺序):自下而上
- 执行顺序(wrapper函数的执行顺序):自上而下
无参装饰器1模板
无参装饰器2模板
无参装饰器3模板
@outter1>>>index=outter1(warpper2的内存地址) >index=wrapper1的内存地址
@outter2>>>index=outter2(warpper3的内存地址)>index=wrapprer2的内存地址
@outter3 >>>index=outter3(index)>>>index=wrapper3的内存地址
def index():
print('from index')
因为语法糖是将正下方贴贴着的函数的内存地址,当作参数传过来,所以加载时从outter3加载,然后一层层给上方的语法糖传参>>>可以理解为从下往上装饰三次
二、有参装饰器
无参装饰器只能接收一个参数,并且还是函数类型,所以想给装饰器传指定参数就得把装饰器再包一次,让最外面的函数接受参数,返回装饰器的函数体内存地址
语法格式: @装饰器(参数,...)
def 有参装饰器(mode):
def 无参装饰器(func):
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res
return wrapper
retun 无参装饰器
@有参装饰器(1):
def 被装饰对象():
pass
碰到有参装饰器调用执行就是@后面的函数先调一下,得一个结果再跟@联动
第一层被装饰函数体本身,第二层套闭包,要用语法糖,但是只能传函数名字进去,第三层就能转文件进去,所以没有必要第四层了,第三层没有被固定死,前两层都是受限制的
三、装饰器的修复技术(好比隐身雷达)
1.由来
首先,每个函数,没被装饰前,都有自己的名字
比如说
def hi1():
pass
def hi2():
pass
我们打印下这两个函数的名字:
print(hi1.__name__)
print(hi2.__name__)
>>>>
hi1
hi2
# 可以看到,他们自己有自己的名字
给他们套个装饰器后呢?
def wraper(func):
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
@wraper
def hi1():
pass
@wraper
def hi2():
pass
print(hi1.__name__)
print(hi2.__name__)
>>>
inner
inner
# 结果都变成了inner
2.怎么用
>>>from functools import wraps +@wraps(func) # func不固定名字,随便写都行 @wraps(func)用在装饰器的子代码的第一行 做强调
from functools import wraps
def wraper(func):
@wraps(func)
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
@wraper
def hi1():
pass
@wraper
def hi2():
pass
print(hi1.__name__)
print(hi2.__name__)
四、归递函数
1.介绍
函数的递归调用:是函数嵌套调用的一种特殊形式
具体是指:在调用一个函数的过程当中,又直接或者间接地调用到了本身
Python官方对递归调用循环调用的次数有限制,为1000次左右(可能会打断在996之类的次数)
1.自己引用自己
def hi1():
print('你好')
hi1()
hi1()
>>>
执行到报错
2.别人引用自己
def hi1():
print('你好')
hi2()
def hi2():
print('你真好')
hi1()
hi1()
>>>
运行到报错
其实上面的两个例子,都可以用while 或者for来做到,由此我们可以知道,如果想让一段代码循环,可以再加一种方法, 这个方法就是递归函数
原则:递归不应该一直无限循环下去,应该满足某一条件就停止运行
2.两个阶段:
-
回溯
就是从外向里一层一层递归调用下去,回溯阶段必须要有一个明确地结束条件,每进入下一次递归时,都应该更接近答案(否则,单纯地重复调用自身是毫无意义的)
-
递推
就是从里向外一层一层结束递归
"""
get_age(5) = get_age(4) + 2
get_age(4) = get_age(3) + 2
get_age(3) = get_age(2) + 2
get_age(2) = get_age(1) + 2
get_age(1) = 18
"""
def get_age(n):
if n == 1:
return 18
return get_age(n-1) + 2 # 为什么碰到return不结束,因为还有函数体没运行完
res = get_age(5)
print(res)
四、作业
1.利用递归函数依次打印列表中每一个数据值
l1 = [1,[2,[3,[4,[5,[6,[7,[8,]]]]]]]]
l1 = [1,[2,[3,[4,[5,[6,[7,[8,]]]]]]]]
# l1 = [1,x]
# 我们的答案是,让得到的数据值不是列表,只要有数据还是列表,就要一直循环搞
def func(l1):
for i in l1:
if type(i) is list:
# 如果是列表,应该再循环、再判断,即 重新运行本身的代码
func(i)
else:
print(i)
func(l1)
2.利用有参装饰器编写多种用户登录校验策略

浙公网安备 33010602011771号