一、装饰器【重点掌握】
Iterable:可迭代对象
Iterator:迭代器
generator:生成器
decorator:装饰器
概念:已知一个函数,如果需要给该函数增加新的功能,但是不希望修改原函数,在Python中,这种在代码运行期间动态执行的机制被称为装饰器【Decorator】
装饰器的作用:为已经存在的函数或者类添加额外的功能
装饰器的本质:实际上就是一个闭包,内部函数访问外部函数中的变量【函数】
1.基本用法
# 1.闭包
def func1(n):
def func2():
print(n)
func2()
func1(10)
def func1(n):
def func2():
print(n)
return func2
f = func1(10) # f = func2
f()
# 2.装饰器的基本语法
def test(): # 9
print("拼搏到无能为力,坚持到感动自己")
# 装饰器的基本书写步骤
# a.书写闭包
# b.给外部函数设置参数,该参数表示需要被装饰的函数
def outter1(func): # 2
def inner1(): # 3 7
# c.调用原函数【在内部函数中访问外部函数中的变量】
func() # 调用原函数test # 8 10
# d.增加新的功能
print("new~~~~")
return inner1 # 4
# e.调用装饰器【外部函数】
f1 = outter1(test) # func = test f1 = inner1 # 1 5
# f.调用装饰器的内部函数
# print(f1)
f1() # inner1() # 6 11
# 1.原函数有参数
def get_age(age):
print(f"年龄:{age}")
# 需求:书写一个装饰器,需要给get_age函数中的age进行校验
def check_age1(func):
def inner1(n):
# 增加新的功能:校验年龄
if n < 0:
n = -n
# 调用原函数
func(n)
return inner1
f1 = check_age1(get_age)
f1(10)
f1(-10)
# 注意:如果原函数有参,在内部函数中增加新的功能,如果需要对原函数中的参数进行相应的运算
# 则可以给内部函数设置参数
# 2.装饰器的常见的形式
# 注意:装饰器本质是一个函数,对于装饰器或原函数,参数【默认参数,关键字参数,不定长参数】和返回值都可以正常使用
# a.
def test1():
print("test~~~111")
def wrapper1(func):
def inner1():
print("new~~~1111")
func()
return inner1
f1 = wrapper1(test1)
f1()
print("*" * 50)
# b
def test1(n):
print("test~~~222",n)
def wrapper1(func):
def inner1(n):
print("new~~~2222")
func(n)
return inner1
f1 = wrapper1(test1)
f1(10)
print("*" * 50)
# c
def test1(n):
print("test~~~333",n)
return 66
def wrapper1(func):
def inner1(n):
print("new~~~3333")
r = func(n)
print(r)
return inner1
f1 = wrapper1(test1)
f1(10)
print("*" * 50)
# d
def test1(n):
print("test~~~444",n)
return 66
def wrapper1(func):
def inner1(n):
print("new~~~4444")
r = func(n)
print(r)
return 'abc'
return inner1
f1 = wrapper1(test1)
r1 = f1(10)
print(r1)
print("*" * 30)
# 3.@xxx
# 说明:@xxx,xxx表示装饰器的名称,实际是外部函数的函数名
# 语法:将@xxx应用在需要被装饰的函数的声明之前
# 注意:使用@xxx使用装饰器,必须先有装饰器,然后才能使用
def check_age2(func):
print("外部函数")
def inner2(n):
print("内部函数~~~~")
if n < 0:
n = -n
func(n) # 调用原函数
print("外部函数~~~~over")
return inner2
@check_age2 # 相当于f1 = check_age2(get_age2),调用装饰器的外部函数
def get_age2(age):
print(f"年龄:{age}")
get_age2(-18) # 相当于f1(-18),调用装饰器的内部函数
"""
工作原理:
第一步:@check_age2
a.func---->get_age2原
b.get_age2---->inner2
第二步:get_age2(-18)
a.调用inner2,然后执行到func(),才表示调用原函数
"""
# 同一个装饰器同时装饰多个函数,相当于给多个函数同时增加同一个新的功能
# 注意:如果需要同一个装饰器装饰多个函数,为了满足不同函数的参数的需求,则装饰器的内部函数设置为不定长参数
def wrapper(func):
def inner(*args,**kwargs): # 打包
# print(args,kwargs)
# print(*args,**kwargs)
func(*args,**kwargs) # 拆包
print("new!!!!!")
return inner
@wrapper
def f1():
print("111111")
@wrapper
def f2(a,b):
print("22222",a,b)
@wrapper
def f3(num1,num2,num3,num4):
print("3333")
f1()
f2(23,10)
f3(34,6,8,9)
# 【面试题】练习:书写一个装饰器,可以统计任意一个函数的执行时间
import time
# 时间戳:获取当前时间距离1970.1.1 00:00:00的秒数
# print(time.time())
def get_time(func):
def inner(*args,**kwargs):
start = time.time()
func(*args,**kwargs)
end = time.time()
return round(end - start,3)
return inner
@get_time
def test():
for i in range(100000):
pass
r1 = test()
print(r1)
@get_time
def test1(n):
for i in range(n):
pass
r2 = test1(1000000)
print(r2)
2.进阶用法
#多个装饰器装饰同一个函数
# 作用:给同一个函数同时增加多个不同的功能
# a
def wrapper1(func1):
def inner1(*args,**kwargs):
print("第1个装饰器~~~~~start")
func1(*args,**kwargs)
print("第1个装饰器~~~~~end")
return inner1
def wrapper2(func2):
def inner2(*args,**kwargs):
print("第2个装饰器~~~~~start")
func2(*args,**kwargs)
print("第2个装饰器~~~~~end")
return inner2
def wrapper3(func3):
def inner3(*args,**kwargs):
print("第3个装饰器~~~~~start")
func3(*args,**kwargs)
print("第3个装饰器~~~~~end")
return inner3
@wrapper1
@wrapper2
@wrapper3
def test():
print("test~~~~~")
test()
"""
工作原理:
第一部分:调用外部函数
@wrapper1
@wrapper2
@wrapper3
def test():
print("test~~~~~")
a.调用wrapper3,func3---->test原,test---->inner3
b.调用wrapper2, func2--->test【inner3】,test---->inner2
c.调用wrapper1, func1--->test【inner2】,test---->inner1
第二部分:调用内部函数
test()
a.inner1--->func1【inner2】
b.inner2--->func2【inner3】
c.inner3--->func3【test原】
"""
二、函数递归
在实际开发中,递归使用较少,递归的工作效率没有循环高
"""
递归函数:如果一个函数,在函数体这种调用自身
使用递归需要注意的问题:
a.需要找到一个临界值,可以让递归在某个合适的时机下停止下来
b.函数相邻的两次调用之间存在某种规律
"""
# 1.恶意调用
# def a():
# print('aaaa')
# a()
# a()
# 2.递归的正确使用
# a.需求1:报一个数【位置】,获取在斐波那契数列中对应的数
"""
1 2 3 4 5 6 7 8 9 10 11.....
1 1 2 3 5 8 13 21 34 55 89
"""
"""
规律:
a.第1个数和第2个数是固定的,都为1
b.第n个数 = 第n-1个数 + 第n - 2个数
"""
def func(n):
print(n)
if n == 1 or n == 2:
return 1
else:
return func(n - 1) + func(n - 2)
r = func(11)
print(r)
# b.需求:求1~某个数之间的整数和
"""
规律:
a.如果n为1,结果直接为1
b.如果n>=2,则结果为1~n-1之间的数的和 + n
"""
def fn(n):
print(n)
if n == 1:
return 1
else:
return fn(n - 1) + n
r = fn(100)
print(r)