13 python程序的命名规则
1)单词首字母大写,驼峰规则
类名
2)小写字母,单词之间用_分割
模块名、包名、变量名、函数名、方法名
3)大写字母,单词之间用_分割
常量名
4)以_开头(2个下划线),但不以\_结尾
私有变量名、私有方法名(类外不可访问)
5)__开头,__结尾
开头,结尾,一般为python的自有变量,不要以这种方式命名
__doc__
__class__
注意:
_单下划线开头:
弱“内部使用”标识,如:”from hainiu import *”,将不导入所有以下划线开头的对象,包括包、模块、成员;
单下划线结尾_:
只是为了避免与python关键字的命名冲突;
__双下划线开头:
模块内的成员,表示私有成员,外部无法直接调用;
包和模块:模块应该使用尽可能短的、全小写命名,可以在模块命名时使用下划线以增强可读性。同样包的命名也应该是这样的;
14 Python logging 模块应用
logging 模块就好比 java 的 log4j,用来生成指定格式日志。
默认情况下python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET)。
如果不设置logger 名称,默认是root logger。
import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
#---------输出---------------------------------
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message
开发程序,需要把日志输出到控制台或输出到文件,需要先创建logger,然后再配置。
import logging
# 创建一个logger
logger = logging.getLogger('mylogger')
#设置logger的日志级别
logger.setLevel(logging.DEBUG)
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log')
#可以为每个handler设置不同的日志级别,但不要小于logger设置的日志级别,否则失效
fh.setLevel(logging.DEBUG)
# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# 定义handler的输出格式,也就是日志的输出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# 给logger添加handler
logger.addHandler(fh)
logger.addHandler(ch)
# 记录一条日志
logger.info('this is test logger info')
#---------输出---------------------------------
2018-12-23 18:24:30,992 - mylogger - INFO - this is test logger info
其中:
logger:
1)创建多个相同名称的logger,其实只创建了一个logger实例。
2)可以设置logger级别的日志级别,logger下的每个handler 可以设置各自的日志级别,但不要小于logger设置的日志级别,否则失效。
handler:
1)Handler对象负责发送相关的信息到指定目的地,有两个Handler方法:
Handler.setLevel(lel):指定日志级别,低于lel级别的日志将被忽略;
Handler.setFormatter():给这个handler选择一个Formatter;
2)handler有很多种,先介绍下面几种:
logging.StreamHandler:可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息;
logging.FileHandler:用于向一个文件输出日志信息;
logging.handlers.RotatingFileHandler:类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建一个新的同名日志文件继续输出;
logging.handlers.TimedRotatingFileHandler: 通过间隔一定时间就自动创建新的日志文件;
3)TimedRotatingFileHandler的构造函数定义
TimedRotatingFileHandler(filename [,when [,interval [,backupCount]]])
filename:是输出日志文件名的前缀
when:是一个字符串的定义如下:
“S”: Seconds
“M”: Minutes
“H”: Hours
“D”: Days
“W”: Week day (0=Monday)
“midnight”: Roll over at midnight
interval: 是指等待多少个单位when的时间后,Logger会自动重建文件,默认是1,当然,这个文件的创建取决于filename+suffix,若这个文件跟之前的文件有重名,则会自动覆盖掉以前的文件,所以有些情况suffix要定义的不能因为when而重复。
backupCount: 是保留日志个数。默认的0是不会自动删除掉日志。若设10,则在文件的创建过程中,会判断是否有超过这个10,若超过,则会从最先创建的开始删除。
除了上述参数之外,TimedRotatingFileHandler还有两个比较重要的成员变量,它们分别是 suffix 和 extMatch 。
suffix 是指日志文件名的后缀,suffix中通常带有格式化的时间字符串,filename和suffix由“.”连接构成文件名(例如:filename=“runtime”, suffix=“%Y-%m-%d.log”,生成的文件名为runtime.2015-07-06.log)。
extMatch 是一个编译好的正则表达式,用于匹配日志文件名的后缀,它必须和suffix是匹配的,如果suffix和extMatch匹配不上的话,过期的日志是不会被删除的。比如,suffix=“%Y-%m-%d.log”, extMatch的只应该是re.compile(r”^\d{4}-\d{2}-\d{2}.log$”)。
默认情况下,在TimedRotatingFileHandler对象初始化时,suffxi和extMatch会根据when的值进行初始化:
‘S’: suffix=”%Y-%m-%d_%H-%M-%S”, extMatch=r”\^d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}”;
‘M’: suffix=”%Y-%m-%d_%H-%M”, extMatch=r”^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}”;
‘H’: suffix=”%Y-%m-%d_%H”, extMatch=r”^\d{4}-\d{2}-\d{2}_\d{2}”;
‘D’: suffxi=”%Y-%m-%d”, extMatch=r”^\d{4}-\d{2}-\d{2}”;
‘MIDNIGHT’: ”%Y-%m-%d”, extMatch=r”^\d{4}-\d{2}-\d{2}”;
‘W’: ”%Y-%m-%d”, extMatch=r”^\d{4}-\d{2}-\d{2}”;
如果对日志文件名没有特殊要求的话,可以不用设置suffix和extMatch,如果需要,一定要让它们匹配上。
Formatter:
指定输出的格式和内容,format可以输出很多有用信息;
format参数中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s用户输出的消息
按秒滚动日志 + 保留10个日志文件:
代码配置:
测试代码:
if __name__ == '__main__':
import time
while True:
b = LogUtil().get_base_logger()
b.info("111")
b.error("222")
try:
1/0
except:
b.exception()
time.sleep(1)
效果:
测试完上面的把配置改成按天滚动文件
LogUtil 的应用
#-*- encoding: utf-8 -*-
'''
log_util_demo.py
Created on 21-9-11 上午10:21
Copyright (c) 21-9-11, 海牛学院版权所有.
@author: 野牛
'''
from commons.util.log_util import LogUtil
logger1 = LogUtil().get_logger("logname", "filename")
logger2 = LogUtil().get_logger("logname", "filename")
# 测试单例模式
print(logger1 is logger2)
logger1.info("打印info信息")
logger1.error("打印info信息")
try:
1/0
except Exception as e:
logger1.exception(e)
注意:如果日志目录不存在,报错
单例设计模式:
单例对象的类必须保证只有一个实例存在。
对单例的实现可以分为两大类
懒汉式:指全局的单例实例在第一次被使用时构建。
饿汉式:指全局的单例实例在类装载时构建。
懒汉式代码:
public class SingleTest2 {
public static void main(String[] args) {
System.out.println(Singleton2.getInstance());
System.out.println(Singleton2.getInstance());
}
}
// 懒汉式
// 优点:只有用到了该对象,才会创建对象
// 缺点:线程不安全(在多线程下创建的不是一个对象)
class Singleton2 {
private static Singleton2 instance = null;
// 私有构造
private Singleton2(){}
// 公有get,在get时才创建
public static Singleton2 getInstance(){
if(instance == null){
instance = new Singleton2();
}
return instance;
}
}
饿汉式代码:
public class SingleTest1 {
public static void main(String[] args) {
System.out.println(Singleton1.getInstance());
System.out.println(Singleton1.getInstance());
System.out.println(Singleton1.getInstance());
}
}
// 饿汉式
// 优点:可以保证线程安全(在多线程下也是一个对象)
// 缺点:由于类初始化时已经创建对象,不能保证在实际使用过程中配合的数据能提前生成
class Singleton1 {
// 类初始化时已经创建对象
private static Singleton1 INSTANCE = new Singleton1();
// 私有构造器
private Singleton1(){}
// 公有get方法
public static Singleton1 getInstance(){
return INSTANCE;
}
}
推荐的代码:
public class SingleTest3 {
public static void main(String[] args) {
System.out.println(Singleton3.getInstance());
System.out.println(Singleton3.getInstance());
System.out.println(Singleton3.getInstance());
}
}
// 静态内部类实现单例
// 优点:只有用到的时候才加载,线程安全(推荐)
class Singleton3 {
// 私有静态内部类,内部实现恶汉单例
private static class SingletonHolder {
private static final Singleton3 INSTANCE = new Singleton3();
}
// 私有构造
private Singleton3(){}
// 公有get,当调用该方法时,内部类才会加载,有且只加载一次
public static final Singleton3 getInstance() {
return SingletonHolder.INSTANCE;
}
}