闭包
定义
什么是闭包
• 在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生 闭包。
•闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。
• 在给定函数被多次调用的过程中,这些私有变量能够保持其持久性
闭包的概念很简单:一个可以引用在函数闭合范围内变量的函数。即"内部函数",只有那个内部函 数才有所谓的__closure__属性。
闭包的好处
闭包的好处
• 闭包不是必须的。
• 没了闭包,python的功能一点不会被影响
• 有了闭包,只是提供给你一种额外的解决方案
装饰器
什么是装饰器
装饰器其实就是闭包
装饰器是这样一种设计模式:如果一个类(函数)希望添加其他类(函数)的一些功能,而不希望通过继承或是直接修改源代码实现,那么可以使用装饰器模式。
•简单来说Python中的装饰器就是指某些函数或其他可调用对象,以函数或类作为可选输入参数,然后返回函数或类的形式。通过这个在Python2.6版本中被新加入的特性可以用来实现装饰器设计 模式。
• 装饰器就是一个可以接受调用也可以返回调用的函数,该函数接受被装饰的函数作为其位置参数。装饰器通过使用该参数来执行某些操作,然后返回原始参数或一些其他的调用
• 函数也是对象,也可以当做参数传递
装饰器有什么用
• 你可以考虑在装饰器中置入通用功能的代码来降低程序复杂度。例如,可以用装饰器来:
• 引入日志
• 增加计时逻辑来检测性能
• 给函数加入事务的能力
• 权限控制
应用多个装饰器
•装饰器函数在被装饰函数定义好后立即执行从下往上执行
函数调用时从上到下执行
如:
import logging
logger=logging.getLogger()
fh=logging.FileHandler("sc.log",encoding='utf-8')
ch=logging.StreamHandler()
foematter=logging.Formatter("%(asctime)s-%(levelname)s:%(message)s")
fh.setFormatter(foematter)
ch.setFormatter(foematter)
logger.addHandler(fh)
logger.addHandler(ch)
logger.setLevel(logging.DEBUG)
def Name(func):
print("i am name1")
def inner(*args,**kwargs):
print("i am name2")
re=func(*args,**kwargs)
logger.warning(f"执行了{func.__name__}函数")
return re
return inner
import time
def Time(func):
print("i am time1")
def inner(*args,**kwargs):
print("i am time2")
start=time.time()
re=func(*args,**kwargs)
end=time.time()
print(f"共花费了{end-start}")
return re
return inner
@Time
@Name
def func(a):
time.sleep(2)
return a
print(func("af"))
从下到上依次执行,结果:
i am name1
i am time1
i am time2
i am name2
共花费了2.010303020477295
af
2021-08-02 15:16:11,351-WARNING:执行了func函数
日志
日志是一种可以追踪某些软件运行时所发生事件的方法
通过日志可以做什么事情?
1、排错
分析和定位故障
2、程序调试
了解程序的运行情况,是否正常
3、用户行为分析
python logging 模块
五个日志级别:(处理事情要分一个轻重缓急)
日志等级 数值表示 描述
DEBUG 10 最详细的日志信息,常用于调试
INFO 20 详细日志信息仅次于DEBUG,记录关键节点的信息
WARNING 30(默认等级) 当前有不期望的事情发生
ERROR 40 发生错误问题导致某些功能不能正常使用
CRITICAL 50 发生了严重错误导致程序不能运行了
logging 日志系统的四大组件
#日志器 Logger
#处理器 Handler
#过滤器 Filter
#格式器 Formatter
# import logging
# LOG_FORMAT = "%(asctime)s-%(levelname)s:%(message)s"
# DATE_FORMAT = "%m/%d/%Y %H:%M:%S"
# logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT,
# datefmt=DATE_FORMAT, filename="my.log")
# logging.debug("this is debug message")
# logging.info("this is info message")
# logging.warning("this is warning message")
# logging.error("this is error message")
import logging
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
#获取logger对象,用于记录日志
logger = logging.getLogger()
#handler对象,用于写入日志,规定日志输出到哪里
#写入文件
#fh = logging.FileHandler("my.log")
#日志轮转
fh = RotatingFileHandler("my.log", maxBytes=500, backupCount=2)
#按照两天时间轮转一次,保留三个备份
# fh = TimedRotatingFileHandler("my.log", when="D", interval=2, backupCount=3)
#输出到屏幕
ch = logging.StreamHandler()
#创建formatter,用于处理日志格式
formatter = logging.Formatter("%(asctime)s-%(levelname)s:%(message)s")
#绑定formatter到hander上
fh.setFormatter(formatter)
#绑定handler到logger对象上
logger.addHandler(fh)
logger.addHandler(ch)
#设置日志等级
logger.setLevel(logging.DEBUG)
for i in range(1000):
logger.warning("this is warning....")
#生成logger对象的时候,没有传递参数进去,那生成的就是root logger 类似 /
#传递name进去之后 类似 /sc
#子日志器会继承父日志器的配置
# logger2 = logging.getLogger("sc")
# logger2.warning("this is sc2 logger")
#
# #类似/sc/xx
# logger3 = logging.getLogger("sc.xx")
# logger3.warning("test test test")
例子
#作业编写日志记录装饰器
#比如执行了func1函数,那就日志记录“执行了func1函数,花费多久时间” ,日志的格式要包含时间
#日志要输出到文件(xu.log)和屏幕
import logging
import time
#获取logger对象,用于记录日志
logger = logging.getLogger()
logger.setLevel(logging.INFO)
#handler对象,用于写入日志,规定日志输出到哪里
#输出到文件
fh = logging.FileHandler("xu.log")
#输出到屏幕
ch = logging.StreamHandler()
#时间格式
format=logging.Formatter("%(asctime)s,%(message)s")
fh.setFormatter(format)
ch.setFormatter(format)
# 绑定handler
logger.addHandler(fh)
logger.addHandler(ch)
def defpro(func):
def inner():
start=time.time()
func()
end=time.time()
logger.info("执行了%s函数,花费%s"%(func.__name__,end-start))
return inner
@defpro
def fun1():
time.sleep(2)
@defpro
def fun2():
time.sleep(1)
fun2()
fun1()
fun2()
执行结果为:
2021-08-02 14:56:12,495,执行了fun1函数,花费2.0094385147094727
2021-08-02 14:56:13,498,执行了fun2函数,花费1.0029654502868652