闭包与装饰器
变量的生命周期:函数调用完了就释放里面的变量
什么是闭包
• 在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。
• 闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。
• 在给定函数被多次调用的过程中,这些私有变量能够保持其持久性
def outer(x):
a=300
def inner():
print(x+a)
return inner
d=outer(100)
d()#输出为400 说明a与x并没有被释放 闭包了(外函数调用的变量并没有随着外函数调用完而释放)
闭包满足的条件:
1.必须要有内嵌函数
2.内函数必须引用外函数的变量
3.外函数必须返回内函数
闭包后,内函数会多一个非空的__closure__属性,保存的是未被释放的变量(外函数的__closure__里面为NONE)
def outer():
tmp=[]
def inner(name):
tmp.append(name)
print(tmp)
return inner
d1=outer()
d1("d1") ['d1']
d1("d1") ['d1', 'd1']
d2=outer()
d2("d2") ['d2']
d2("d2") ['d2', 'd2']
每次调用外函数都会重新执行,创建一个新的tmp和list
虽然代码都一样 但是创建的对象是不一样的
只要inner函数还在 tmp也就一直在
闭包的好处
• 闭包不是必须的。
• 没了闭包,python的功能一点不会被影响
• 有了闭包,只是提供给你一种额外的解决方案
装饰器:是一种程序设计模式,主要用于给函数或类添加一些额外的功能 又不希望通过继承或者修改源代码的方式去实现,那就使用装饰器
(总的来说 就是不改变函数或类的源代码基础上,添加额外功能)
装饰器的本质就是闭包函数,它需要把一个callable(函数,类(也就是可以打括号运行的对象))对象作为参数传递进来
统计运行时间的装饰器
import time
def runtime(func):
def inner():
start=time.time()
func()
end=time.time()
print(f"执行函数花了{end-start}s")
return inner
@runtime
def func1():
time.sleep(2)
print("func1.....")
@runtime # 相当于 func1=runtime(func1)
def func2():
time.sleep(1)
print("func2.....")
func1() 于是就相当于就是在运行inner函数
func2()
执行结果:
func1.....
执行函数花了2.0078823566436768s
func2.....
执行函数花了1.0153162479400635s
@被称为修饰符
得到原函数的返回值
def runtime(func):
def inner():
return func()
return inner
@runtime
def func1():
return 3
r=func1()
print(r)
若func有参数时:
def runtime(func):
def inner(*args,**kwargs):#可变长位置参数和可变长关键字参数 可传可不传
return func(*args,**kwargs)
return inner
@runtime
def func1(a,b):
print(a+b)
func1(1,2)
@runtime
def func2():
return 3
print(func2())
装饰器的应用:
添加额外功能:
计时
权限控制
日志记录
日志:记录软件运行过程中发生的事件
通过日志可以做什么?
1.程序调试(了解程序的运行情况是否正常)
2.排错(分析和定位故障)
3.用户行为分析
python里面的日志处理模块(logging 模块处理日志):这是内建模块
五个日志等级:
日志等级 数值表示 描述
1.DEBUG 10 最详细的日志信息,开发过程中用于诊断问题
2.INFO 20 详细日志信息仅次于debug 记录关键节点的信息
3.WARNING 30(默认) 当前不期望的事情发生
4.ERROR 40 发生错误问题导致某些功能不能正常使用
5.CRITICAL 50 发生严重错误导致程序不能继续运行
程序默认日志等级一般设置为warning 表示显示warining以上的日志
log_format="%(asctime)s - %(filename)s - %(levelname)s:%(message)s"
logging.basicConfig(level=logging.DEBUG, format=log_format, filename="a.log")
#表示把系统默认日志等级改为debug,且规定日志输出格式,且指定输出到a.txt文件里面(不输出到屏幕)
logging.warning("waring")
logging.error("error")
logging.debug("debug") #DEBUG:root:debug 会显示默认的日志格式
logging日志系统的四大组件
日志器 logger
处理器 handler
过滤器 filter
格式器 formatter
更加灵活的记录
import logging
#得到一个日志器 日志器用来记录日志
logger=logging.getLogger()
#处理器 就是决定日志要发送到哪里
fh=logging.FileHandler("SC.log")#把等会记录的日志发送到sc.log 要是没有参数 则是在当前
ch=logging.StreamHandler()#把等会记录的日志输出到屏幕
#将handler绑到logger对象上才能使用
logger.addHandler(fh)
logger.addHandler(ch)
#直接输出括号里的内容 无任何格式 既到文件又到屏幕
logger.warning("this is warining...")
#于是我们需要自己定义格式
formatter=logging.Formatter("%(asctime)s - %(filename)s - %(levelname)s:%(message)s")
#绑定formatter到handler上
fh.setFormatter(formatter)#对于写入文件的处理器绑定格式 对于输到屏幕的不一样
logger.warning("warining...")
日志器层级关系 类似于继承
getLogger不传参数,我们称为根日志器 称作root logger (类似/)
传递sc 就是子日志器 (类似于/sc)
子日志器回继承父日志器的一切配置
logger2=logging.getLogger("sc")
logger3=logging.getLogger("sc.a")#logger3继承sc 且名字叫做a
日志的轮转
按时间 日志文件名称接的是时间
按大小 一般日志文件名称接的是大小
Linux里面的logtotate.conf里面可以规定系统几天一轮转以及大小
python里面日志可以在handler里面的一个方法里面设置
'''
装饰器需要统计运行时间
需要统计运行了什么函数,且把函数名放入日志文件
'''
#统计运行时间的装饰器
import time
import logging
import functools
logger = logging.getLogger()
fh = logging.FileHandler("SC.txt")
ch = logging.StreamHandler()
logger.addHandler(fh)
logger.addHandler(ch)
formatter=logging.Formatter("%(asctime)s - %(filename)s - %(levelname)s:%(message)s")
fh.setFormatter(formatter)
#统计运行时间的装饰器
def runtime(func):
@functools.wraps(func)
def inner(*args,**kwargs):
start=time.time()
result=func(*args,**kwargs)
end=time.time()
print(f"执行函数花了{end-start}s")
logger.warning(f"执行函数花了{end-start}s")
return result
return inner
def name(func):
#保留元数据,将传进去的func的元数据全部复制给inner
def inner(*args,**kwargs):
result=func(*args,**kwargs)
print(f"正在运行{func.__name__}函数")
logger.warning(f"正在运行{func.__name__}函数")
return result
return inner
#第一种情况 不行
# @runtime #add=runtime(name(add))
# @name #add=name(add) #name放在后面时间不对(时间包括了name里inner运行的时间) name放在前面名字不对
#所以只能保留源数据
@name #add=name(runtime(add))
@runtime #add=runtime(add)
def add(a,b):
time.sleep(2)
print(1111)
return a+b
print(add(1,2))
装饰器的用途就是不改变原代码的情况下 增加额外的功能
所以每个装饰器在原函数有返回值的情况下 最好运行一下func 并且return result
operate函数python pythonupper函数
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
python查询汉字函数
python查询汉字函数
数据集 机器学习 特征提取 -
python函数详解(定义、参数、返回值、高级函数、偏函数、装饰器)
这是python中的基础系列中的关于函数部分,来开始我们今天日拱一卒!对python函数部分进行详细整理和学习。
python Python Python函数 Python装饰器 Python高级函数 -
系统架构设计师教程第二部PDF
今天清晨,酷寒过去后,阴雨天,突然有种想写有关系统架构方面的博文,上周本就应开始,不过还是今天感觉比较强烈,此处只是粗列了一些比较痛的领悟一、目标系统特征:快速、稳定、可扩展性、安全 1.快速保障:数据结构+程序逻辑设计+硬件+网络 2.稳定保障:监控 3.
系统架构设计师教程第二部PDF 系统架构 数据结构与算法 数据库 可扩展性