Python5
Python1-环境配置
Python2-基础认识
Python3-数据类型
Python4-面向对象
Python5-闭包和装饰器
Python6-IO 模块
Python7-进程线程携程
Python8-网络编程
Python 爬虫
闭包和装饰器
闭包
在函数的嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数的引用,这个使用外部函数变量的内部函数称为闭包
- 在函数嵌套的前提下
- 内部函数使用外部函数的变量(包含参数)
- 外部函数返回内部函数
闭包就是内函数的引用+外函数的执行过程
在外函数的嵌套条件下,执行内函数,相当于内函数保存了外函数的内部变量
闭包的写法
# 定义一个外部函数
def func_out(num1):
num3 = 5
# 定义一个内函数
def func_inner(num2):
print(num3)
result = num1 + num2
print('结果是',result)
return func_inner
# 这个运行就是闭包的优点
# 创建闭包实例
ret = func_out(1)
# 运行闭包
ret(2)
类和闭包对比
实现效果一样,但是闭包更加轻量级
# class Person(object):
# def __init__(self,name) -> None:
# self.name = name
# def say(self,msg):
# print(self.name + 'Say:' + msg)
# tom = Person('tom')
# jack =Person('jack')
# tom.say('ni hao')
# jack.say('ni hao')
def person(name):
def say(msg):
print(name + 'Say:' + msg)
return say
tom = person('tom')
jack = person('jack')
tom('ni hao')
jack('ni hao')
内部函数修改外部变量
内部函数不能直接修改外部变量,需要使用 nonlocal 进行声明
def outer():
n=1
def inner():
nonlocal n
n = n + 10
print(n)
print(n)
return inner
ret = outer()
ret()
ret()
装饰器
给已有函数增加额外的功能
- 不修改已有函数的源代码
- 不修改已有函数的调用方式
- 给已有函数增加额外的功能
解释装饰器原理
import time
# 方式一
# def show():
# start = time.time()
# n = 0
# for i in range(10000000):
# n += i
# print('show - ', n)
# end = time.time()
# times = end - start
# print('时间',times)
# show()
# 方式二
# def show():
# n = 0
# for i in range(10000000):
# n += i
# print('show - ', n)
# def count_time(func):
# start = time.time()
# func()
# end = time.time()
# print('时间:',end - start)
# count_time(show)
# 方式三
# 没有改变源函数的代码
def show():
n = 0
for i in range(10000000):
n += i
print('show - ', n)
# 增加的功能
def count_time(func):
def inner():
start = time.time()
func()
end = time.time()
print('时间:',end - start)
return inner
# 装饰器装饰的原理
show = count_time(show)
# 没有改变源调用方式
show()
装饰器语法糖写法
python 提供了一个装饰器的简单写法,
在要被调用的函数前使用@装饰器名,用来省略 show = count_time(show),
装饰器名就是外函数名,闭包要提前定义
def count_time(func):
def inner():
start = time.time()
func()
end = time.time()
print('时间:',end - start)
return inner
@count_time # ->show = count_time(show)
def show():
n = 0
for i in range(10000000):
n += i
print('show - ', n)
show()
通用装饰器
无参数无返回值
def outer1(func):
def inner():
print('装饰内容1')
func()
print('装饰内容2')
return inner
@outer1
def show1():
print('show1...')
show1()
有参数无返回值
def outer2(func):
def inner(msg):
print('装饰内容1')
func(msg)
print('装饰内容2')
return inner
@outer2
def show2(msg):
print('show2...',msg)
show2('python')
无参数有返回值
def outer3(func):
def inner():
print('装饰内容1')
ret = func()
print('装饰内容2')
return ret
return inner
@outer3
def show3():
return 'show3...'
print(show3())
有参数有返回值
def outer4(func):
def inner(msg):
print('装饰内容1')
ret = func(msg)
print('装饰内容2')
return ret
return inner
@outer4
def show4(msg):
return 'show4...'+msg
print(show4('python'))
通用装饰器
def outer(func):
# 组包,*args组成元组,**kwargs组成数组
def inner(*args,**kwargs):
print('装内容1...')
# 拆包
ret = func(*args,**kwargs)
print('装内容2...')
return ret
return inner
@outer
def show1():
print('show1...')
show1()
@outer
def show2(msg):
print('show2...',msg)
show2('python')
@outer
def show3():
return 'show3...'
print(show3())
@outer
def show4(msg):
return 'show4...'+msg
print(show4('python'))
@outer
def show2(msg,n):
print('show2...',msg,n)
show2('python',1)
一函数多装饰器
装饰器从上到下装饰,执行从上到下执行
# 第一个闭包
def wrapper_div(func):
def inner(*args,**kwargs):
return '<div>'+func(*args,**kwargs)+'</div>'
return inner
# 第二个闭包
def wrapper_p(func):
def inner(*args,**kwargs):
return '<p>'+func(*args,**kwargs)+'</p>'
return inner
# 修饰器1
@wrapper_div
# 修饰器2
@wrapper_p
# 函数
def show():
return 'Short Life I use Python'
print(show())
装饰器类写法
将类转化为可调用对象
class Person():
def __call__(self,*args,**kwargs):
print('Call Run...')
tom = Person()
print(callable(tom))
tom()
装饰器类写法
class Wrapper(object):
def __init__(self,func) -> None:
self.func = func
# 相当于闭包当中的内函数
# 调用装饰器类对象时,会自动调用__call__方法
def __call__(self,*args,**kwargs):
print('装饰内容1')
ret = self.func(*args,**kwargs)
print('装饰内容2')
return ret
@Wrapper
def show():
print('Show Run...')
show()
类装饰器
class a():
def car(self):
print('Car Run...')
class b(a):
def car(self):
print('Car Stop...')
if __name__ == '__main__':
a().car()
b().car()
这样 a 类当中的 car 方法在 b 类当中被重写了,根据这个原理可以实现类装饰器
def class_wrapper(clr):
class Wrapper(clr):
def __init__(self, *args, **kwargs):
print('Wrapper init')
super().__init__(*args, **kwargs)
def car(self):
print('Wrapper Car Run...')
return Wrapper
@class_wrapper
class a():
def car(self):
print('Car Run...')
if __name__ == '__main__':
a().car()
这样写比较好笑,不如直接用继承,可能是为了不修改调用的方法。
装饰器传参
理论
# 无论闭包函数被定义成什么样子,在使用闭包进行装饰函数时,被装饰的函数,永远指向闭包函数的内函数
# 第一层接收装饰器的参数
def set_args(msg):
# 第二层接收被装饰的函数
def set_func(func):
# 第三层装饰功能
def inner():
print('装饰内容'+msg)
func()
return inner
return set_func
@set_args('hello') # -> @set_func(func)且msg赋值为'hello'
def show():
print('Show Run...')
show()
应用
使用装饰器传参实现自动维护路由
路由:通过一个路径,去找找到一个资源
# 定义一个空路由表
router_table = {}
# 定义一个用来进行自动维护路由的装饰器(带参)
def router(url):
def wrapper(func):
def inner():
func()
# 在这维护路由表,表一定要填inner,这样inner内还可以定义方法
router_table[url] = inner
return inner
return wrapper
@ router('index.html')
def index():
print('首页内容')
@ router('center.html')
def center():
print('个人中心')
@ router('mail.html')
def mail():
print('邮箱页面')
@ router('login.html')
def login():
print('登录页面')
def error():
print('访问页面不存在')
# router_table = {'index.html':index, 'center.html':center}
def request_url(url):
func=error
if url in router_table:
func = router_table[url]
func()
request_url('index.html')
request_url('center.html')
request_url('mail.html')
request_url('login.html')

浙公网安备 33010602011771号