Python之闭包函数、装饰器

时间:2023-03-09 04:48:17
Python之闭包函数、装饰器

1、闭包函数

#作用域关系在函数定义阶段时就已经固定死了,与调用位置无关
# 即:在任意位置调用函数都需要跑到定义函数时寻找作用域关系 # def f1():
# x=1
# def inner():
# print(x) #闭包的含义:内部函数中的变量x引用外部作用域的x,而非全局作用域的x
# return inner
# func=f1() #f1()=inner
#
#
# def f2():
# x=111111
# func() #func()=inner()
# f2() # 闭包函数:
# 闭指的是:该函数是一个内部函数
# 包指的是:指的是该函数包含对外部作用域(非全局作用域)名字的引用
# def outter():
# x = 1
# def inner():
# print(x) #内部函数inner中的x是对外部作用域的引用,而非全局作用域的引用
#
# return inner
#
# f=outter()
#
# def f2():
# x=1111111
# f()
#
# f2()
#
#
# def f3():
# x=4444444444444
# f()
#
# f3() # 为函数传值的两种方式:
# 为函数体传值的方式一:使用参数的形式
# def inner(x):
# print(x)
#
# inner(1)
# inner(1)
# inner(1) # 为函数体传值的方式二:包给函数
'''
def outter(x):
# x=1
def inner():
print(x) #通过闭包函数将值报给内部函数
return inner f=outter(1)
f()
''' # 例子:
# 方法一:通过传参的形式将值传给函数内的变量
# import requests
# def get(url):
# response=requests.get(url)
# if response.status_code == 200:
# print(response.text)
#
# get('https://www.baidu.com')
# get('https://www.baidu.com')
# get('https://www.baidu.com')
#
# get('https://www.python.org')
# get('https://www.python.org')
# get('https://www.python.org')
# get('https://www.python.org') # 方法二:通过闭包函数将值包给其内部的函数
import requests
def outter(url): #通过传参的形式,可以爬去任意网页的源代码
# url='https://www.baidu.com' #功能被写死,所以改成传参的形式
def get():
response=requests.get(url) #url是通过outter函数,将值包给函数get内的函数体代码用的
if response.status_code == 200: #成立说明,成功爬去网页的源代码
print(response.text)
return get #返回get给外部的调用者,打破层级的限制(函数对象的知识) baidu=outter('https://www.baidu.com') #本质就是传入了参数的get的内存地址
python=outter('https://www.python.org') baidu() #本质就是已经给url传入了参数的get的内存地址,加括号即调用
baidu() python()
python()

2、装饰器

'''
1、什么是装饰器
器指的是工具,而程序中的函数就具备某一功能的工具
装饰指的是为被装饰器对象添加额外功能 就目前的知识来看:
定义装饰器就是定义一个函数,只不过该函数的功能是用来为
其他函数添加额外的功能 其实:
装饰器本身其实可以是任意可调用的对象
被装饰的对象也可以是任意可调用的对象 2、为什么要用装饰器
软件的维护应该遵循开放封闭原则
开放封闭原则指的是:
软件一旦上线运行后对修改源代码是封闭的,对扩展功能的是开放的
这就用到了装饰器 装饰器的实现必须遵循两大原则:
1、不修改被装饰对象的源代码
2、不修改被装饰对象的调用方式
装饰器其实就在遵循1和2原则的前提下为被装饰对象添加新功能 3、如何用装饰器
''' # 方式一
# 给原函数添加上了新功能,没有改变原函数的调用方式,但是却改变了源代码
import time
# def index():
# start=time.time()
# print('welcom to index')
# time.sleep(3)
# stop=time.time()
# print('run time is %s' %(stop-start))
# index() # 方法二
# 没有改变源代码,也没有改变调用方式,但是给不同函数扩展相同的功能时,是在重复写代码的过程
import time
# def index():
# print('welcom to index')
# time.sleep(3)
#
# def f2():
# print('from f2')
# time.sleep(2) # 以下为两个函数添加上了引得功能,但是重复写代码
# start=time.time()
# index()
# stop=time.time()
# print('run time is %s' %(stop-start))
# #
# start=time.time()
# f2()
# stop=time.time()
# print('run time is %s' %(stop-start)) # 方法三
# 将重复写代码的过程,定义为一个函数的功能,虽然没有该源代码,但是改变了函数的调用方式
# import time
#
# def index():
# print('welcom to index')
# time.sleep(3)
#
# def timmer(func):
# start=time.time()
# func()
# stop=time.time()
# print('run time is %s' %(stop-start))
#
# timmer(index) # 方法四
# 利用闭包函数,为函数添加上新的功能 '''
import time
def index():
print('welcom to index')
time.sleep(3) def timmer(func): #func=最原始的index
# func=index #这样就把被装饰的对象写死了,所以需要以传参的形式将,被装饰的函数传进来
def inner():
start=time.time()
func()
stop=time.time()
print('run time is %s' %(stop-start))
return inner # f=timmer(index)
# f() # index=timmer(被装饰函数的内存地址)
index=timmer(index) #index=inner index() #inner() '''
import time def index():
print('welcom to index')
time.sleep(3) def timmer(func): #将被装饰的函数传进来,不至于将被装饰的对象写死,固定是某一个,而是可以装饰任意一个函数
#func=最原始的index ,即被装饰函数的的内存地址
def wrapper(): #该函数即是为被装饰函数添加上的新功能
start=time.time()
func() #最原始的index加括号即使调用最原始的函数
stop=time.time()
print('run time is %s' %(stop - start))
return wrapper #函数对象知识:返回给外部函数调用,打破层级限制 index=timmer(index) #左边的index=wrapper函数的内存地址,右边的index即是我们要装饰的函数
index() #本质调用的是wrapper函数

三、装饰器修正

import time
def index(): #被装饰的函数无参,有返回值
print('welcome to index')
time.sleep(3)
return 123 def home(name): #被装饰的函数有参,没有返回值
print('welcome %s to home page' %name)
time.sleep(2) def timmer(func):
#func=最原始的index
def wrapper(*args,**kwargs): #wrapper会将接收的参数,原封不动的传给被装饰的函数
start=time.time()
res=func(*args,**kwargs) #因为被装饰的对象可能有的有参,有的是无惨,所以调用时用*args,**kwargs,无论有无参数都不会报错
stop=time.time()
print('run time is %s' %(stop - start))
return res #接收被装饰函数的返回值,被装饰的函数没有返回值则为None,有则返回被装饰的返回值
return wrapper #该返回值则是返回给外部函数用的,可以打破层级的限制,这样内部函数即给被装饰函数添加的新功能就可以被调用到 index=timmer(index) #将被装饰的函数传入,调用装饰器,本质就是调内部被加上新功能的函数
home=timmer(home) #将被装饰的函数传入,调用装饰器,本质就是调内部被加上新功能的函数 res=index() #拿到调用函数的返回值,打印即可看到返回值
home('egon') #被装饰的函数为有参,为被装饰函数进行传参
print(res) #装饰器语法糖
# 在被装饰对象正上方,并且是单独一行写上@装饰器名
# import time
# def timmer(func):
# #func=最原始的index
# def wrapper(*args,**kwargs):
# start=time.time()
# res=func(*args,**kwargs)
# stop=time.time()
# print('run time is %s' %(stop - start))
# return res
# return wrapper
#
# @timmer # index=timmer(index) #timmer即一个名字,所以装饰器的代码块要写在timmer的上方,@timmer本质就是调用了timmer(传入被装饰的函数名)
# def index():
# print('welcome to index')
# time.sleep(3)
# return 123
#
# @timmer # home=timmer(home)
# def home(name):
# print('welcome %s to home page' %name)
# time.sleep(2)
#
# res=index()
# home('egon') # 装饰器的万能模板:
def deco(func): #func即是要接收的被砖石的函数名
def wrapper(*args,**kwargs): #可以根据被装饰的函数需不需要传参,给被装饰的对象传入参数
res=func(*args,**kwargs) #本质就是调用被装饰的函数, 接收传进来的参数
return res #接收被装饰函数的返回值,没有则返回None
return wrapper #外部函数将内部函数的内存地址返回,打破层级限制