项目开发规范、time模块、日志

. 昨日内容回顾
自定义模块
import tbjx

1.创建一个以 tbjx 命名的名称空间
2.执行此模块的代码,并将所有内容加载到内存
3.调用此模块的代码要通过 tbjx. 的方式

改名:
import time as t
1.使代码更简洁
2.优化代码

import a
import b
import c

from tbjx import name,read1
1.创建一个以 tbjx 命名的名称空间
2.执行此模块的代码,并将所有内容加载到内存
3.直接将 name read1 加载到当前文件的全局中
好处:使用方便
缺点:容易与本文件同名的变量,函数冲突

from tbjx import functools as func

from tbjx import *
1.创建一个以 tbjx 命名的名称空间
2.执行此模块的代码,并将所有内容加载到内存
3.直接将 tbjx 模块中所有的内容全部复制一份到当前文件中

__all__ = ["name", "read1"]

文件的使用:
1.当脚本或者代码块,运行本文件的所有代码
2.当作一个模块,被其他模块调用
__name__
本文件使用,相当于 __main__
其他文件,__name__ == "被调用的模块名"

__name__ == "__main__":
1.可以在本模块下,测试自己的代码
2.项目的执行文件使用

解释器是按照一定的顺序和位置去寻找模块
搜索路径:内存--->内置模块--->sys.path[此列表的第一个元素是当前文件的路径]

想在不同的文件夹下调用模块?
将模块的路径添加到sys.path中

import sys
print(sys.modules)
程序一运行,解释器会把所有这些 modules 先加载到内存中



.项目开发规范
代码不可能只写在一个文件中,否则调整和修改都很不方便,所以要将代码规范化:
目录规范化,代码规范化(PEP8)

目录规范化的好处?
1.项目结构清晰,便于查找
2.对项目修改时,易于调试

# 三.time模块,datetime模块

import time
print(time.time())
print(time.sleep(1))

# time模块提供的时间有三种模式
# 第一种形式
# time.time() 时间戳——从1970.1.1 0:00距今的时间,供计算机使用
import time
print(time.time())

# 第二种形式(格式化时间)
# 2019/1/8 10:39 strftime()
import time
ft = time.strftime("%Y-%m-%d")
ft = time.strftime("%Y/%m/%d")
ft = time.strftime("%Y/%m/%d %I%M%S")
ft = time.strftime("%Y{}%m{}%d %I:%M:%S").format("", "", "")
print(ft)  # 2019年01月08 10:55:19

# 第三种形式:结构化时间以元组的形式存在
# 作为格式化时间与时间戳进行转化的中转
import time
struct_time = time.localtime()
print(struct_time)
# time.struct_time(tm_year=2019, tm_mon=1, tm_mday=8, tm_hour=10,
# tm_min=56, tm_sec=56, tm_wday=1, tm_yday=8, tm_isdst=0)
print(struct_time[0])  # 2019
print(struct_time.tm_year)  # 2019

# 三种格式之间的转化
# 时间戳 ---> 格式化时间
import time
timestamp = time.time()
# 先将时间戳转化成结构化时间
st = time.localtime(timestamp)
ft = time.strftime("%Y{}%m{}%d %I:%M:%S", st).format("", "", "")
print(ft)  # 2019年01月08 11:00:59

# 格式化时间 ---> 时间戳
import time
ft = time.strftime("%Y/%m/%d %I:%M:%S")
# 先将格式化时间转化成结构化时间
st = time.strptime(ft, "%Y/%m/%d %I:%M:%S")
print(st)
# time.struct_time(tm_year=2019, tm_mon=1, tm_mday=8, tm_hour=11,
tm_min=3, tm_sec=58, tm_wday=1, tm_yday=8, tm_isdst=-1)

# 另一种转化方式
# 结构化时间 ---> 格式化时间  格式固定
import time
strut_time = time.localtime()
st = time.asctime(strut_time)
print(st)  # Tue Jan  8 11:10:57 2019

# 时间戳 ---> 格式化时间  格式固定
import time
print(time.ctime(15000000000))  # Mon May  1 10:40:00 2445

 

# 时间差的计算
# 2019 1 8 11
# 2016 9 16 12
# 第一步,将这两个格式化时间转化成时间戳

import time
now_time = time.strftime("%Y/%m/%d %H:%M:%S")
now_timestamp = time.mktime(time.strptime(now_time, "%Y/%m/%d %H:%M:%S"))

old_time = time.strftime("2016/9/16 12:00:00")
old_timestamp = time.mktime(time.strptime(old_time, "%Y/%m/%d %H:%M:%S"))

dif_time = now_timestamp - old_timestamp
# print(time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(dif_time)))
struct_time = time.gmtime(dif_time)

msg = "过去了%d年%d月%d天%d小时%d分钟%d秒" % (struct_time.tm_year-1970,struct_time.tm_mon-1,
                                          struct_time.tm_mday-1,struct_time.tm_hour,
                                          struct_time.tm_min,struct_time.tm_sec)
print(msg)  
# 过去了2年3月22天23小时29分钟55秒

 

# datetime

import datetime
now_time = datetime.datetime.now()
print(now_time)  # 2019-01-08 11:30:56.074414
print(now_time + datetime.timedelta(weeks=3))  # 三周前
print(now_time + datetime.timedelta(weeks=3))  # 三周后
# print(now_time + datetime.timedelta(years=3))    # 年没有
print(datetime.datetime.now() + datetime.timedelta(days=-3))      # 三天前
print(datetime.datetime.now() + datetime.timedelta(days=3))       # 三天后
print(datetime.datetime.now() + datetime.timedelta(hours=5))      # 5小时后
print(datetime.datetime.now() + datetime.timedelta(hours=-5))     # 5小时前
print(datetime.datetime.now() + datetime.timedelta(minutes=-15))  # 15分钟前
print(datetime.datetime.now() + datetime.timedelta(minutes=15))   # 15分钟后
print(datetime.datetime.now() + datetime.timedelta(seconds=-70))  # 70秒前
print(datetime.datetime.now() + datetime.timedelta(seconds=70))   # 70秒后

# 可以直接调整
print(now_time.replace(year=2010))  # 2010-01-08 11:34:20.476402
print(now_time.replace(month=10))   # 2019-10-08 11:35:10.009449
print(now_time.replace(year=2010, month=10, day=23))  # 2010-10-23 11:36:25.877321

# 将时间戳转化成时间
print(datetime.date.fromtimestamp(1232132131))  # 2009-01-17

 

.日志
个性化推荐 —— 淘宝,京东,知乎,网易云音乐
只要做了记录,就可以当作广义的日志

开发中的日志
1.帮助调试代码 一个py文件中,使用print()太多,耗费性能大
2.代码警告,危险提示作用
3.对服务器的操作命令
4.重要的节点,需要日志提示,比如转账

 

# 日志分三种配置:

# 低配——不能同时显示和写入
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


import logging
while 1:
    try:
        num = input(">>>")
        int(num)
    except ValueError:
        logging.warning("输入了非数字元素,警告!")

# 指定显示信息格式
import logging
logging.basicConfig(
    level=logging.DEBUG,
    # 可以设置级别 把上面的注释掉,然后写下面的
    # level=20,
    format='%(asctime)s %(filename)s[line:%(lineno)d]                     %(levelname)s %(message)s',
    datefmt='%a, %d %b %Y %H:%M:%S',)
    # filename='/tmp/test.log',
    # filemode='w')

logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
# Tue, 08 Jan 2019 12:14:58 abc.py[line:214]                     DEBUG debug message
# Tue, 08 Jan 2019 12:14:58 abc.py[line:215]                     INFO info message
# Tue, 08 Jan 2019 12:14:58 abc.py[line:216]                     WARNING warning message
# Tue, 08 Jan 2019 12:14:58 abc.py[line:217]                     ERROR error message
# Tue, 08 Jan 2019 12:14:58 abc.py[line:218]                     CRITICAL critical message

默认情况下Pythonlogging模块将日志打印到了标准输出中
且只显示了大于等于WARNING级别的日志
这说明默认的日志级别设置为WARNING
日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG
默认的日志格式为 日志级别: Logger名称: 用户输出消息

 

import logging

logging.basicConfig(level=logging.DEBUG,
                    format="%(asctime)s %(filename)s [line:%(lineno)d]"
                           " %(levelname)s %(message)s",
                    datefmt="%a, %d, %b %Y %H:%M:%S",
                    filename="test.log",
                    filemode="w")

logging.debug("debug message")
logging.info("info message")
logging.warning("warning message")
logging.error("error message")
logging.critical("critical message")

 

灵活配置日志级别,日志格式,输出位置

这个日志是对本文件的记录



以下所谓加上,是指在logging.basicConfig()中,显示是在Logger所属 filename 中

logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为

1. level: 设置rootlogger的日志级别

2. format: 指定handler使用的日志显示格式
format参数中可能用到的格式化信息有以下内容:
%(name)s——Logger的名字
这里如果加上的话,显示是root
%(levelno)s——数字形式的日志级别
这里加上的话逐行显示10,20,30,40,50
%(levelname)s——文本形式的日志级别
%(pathname)s——调用日志输出函数的模块的完整路径名,可能没有
显示本文件的绝对路径
这里加上的话,会有乱码,因为路径中有中文字符
%(filename)s——调用日志输出函数的模块的文件名
这里是本文件名,123asda.py
%(module)s——调用日志输出函数的模块名
这里加上的话,是 123asda
%(funcName)s——调用日志输出函数的函数名
这里加上的话,因为从上面到这里都还没函数
所以显示是 <module>
%(lineno)d——调用日志输出函数的语句所在的代码行
即比如下面的 logging.debug("debug message")
显示是在本文件的第几行,这五个都会显示
%(created)f——当前时间,用Unix标准的表示时间的浮点数表示
这里加上的话,显示 1547727721.904610
%(relativeCreated)d——输出日志信息时间,自Logger创建以来的毫秒数
%(asctime)s——字符串形式的当前时间
比如这里加上显示:Thu, 17, Jan 2019 20:27:49
%(thread)d——线程ID,可能没有
这里加上显示:7536
%(threadName)s——线程名,可能没有
这里加上显示:MainThread
%(process)d——进程ID,可能没有
这里加上显示:7692
%(messages)s——用户输出的消息

3. datefmt: 指定 format 中 asctime 的显示格式

4. filename: 用指定的文件名创建FileHandler,这样日志会被存储在指定的文件中

5. filemode: 文件打开方式,在指定了 filename 时使用这个参数,默认为"a"

6. stream: 用指定的stream创建StreamHandler, 可以指定输出到sys.stderr,
sys.stdout或者文件(f=open("test.log","w")), 默认为sys.stderr.
如果同时列出了filename和stream两个参数,stream会被忽略

 

import logging

# 创建一个logger对象
logger = logging.getLogger()

# 创建一个handler,用于写入日志文件
fh = logging.FileHandler("test.log", encoding="utf-8")
# 设置级别
fh.setLevel(logging.DEBUG)
# 这里 DEBUG 改为 INFO 在 test.log中也只显示 WARNING 以上级别的信息

# 再创建一个handler, 用于输出到控制台
ch = logging.StreamHandler()

# 设置显示格式,并将此格式传到两个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.debug("logger debug message")
logger.info("logger info message")
logger.warning("logger warning message")
logger.error("logger error message")
logger.critical("logger critical message")

# 与本文件同一个目录下,还会创建一个 test.log文件,输出信息和下面的一样
# 2019-01-17 21:01:52,674 - root - WARNING - logger warning message
# 2019-01-17 21:01:52,674 - root - ERROR - logger error message
# 2019-01-17 21:01:52,674 - root - CRITICAL - logger critical message

 

 

# 标配

import logging

# 1.产生 logger 对象
logger = logging.getLogger()

# 2.产生其他对象(屏幕对象,文件对象)
sh = logging.StreamHandler()
fh1 = logging.FileHandler("staff.log", encoding="utf-8")
fh2 = logging.FileHandler("boss.log", encoding="utf-8")

# 3.设置显示格式
formater = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s')
formater1 = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s')
formater2 = logging.Formatter('%(asctime)s-%(message)s')

# 4.给对象绑定格式
sh.setFormatter(formater)
fh1.setFormatter(formater1)
fh2.setFormatter(formater2)

# 5.给 logger 对象绑定其他对象
logger.addHandler(sh)
logger.addHandler(fh1)
logger.addHandler(fh2)

# 6.设置显示级别
# 其他对象的级别要高于 logger 的级别
logger.setLevel(40)
sh.setLevel(20)
fh1.setLevel(30)
fh2.setLevel(50)

logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

# 2019-01-08 12:40:42,240-root-ERROR-error message
# 2019-01-08 12:40:42,240-root-CRITICAL-critical message

 

logging库提供了多个组件:Logger, Handler, Filter, Formatter
Logger对象提供应用程序可直接使用的接口
Handler发送日志到适当的目的地
Filter提供了过滤日志信息的方法


logger的配置文件
上面方式是通过logger对象配置完成日志功能,需要创建各种对象
下面是以字典方式创建logger配置文件,也是实际工作中的做法,相当于一个模板

 

import os
import logging.config

# 定义日志输出格式
standard_format = "[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s]" \
                  "[%(filename)s:%(lineno)d][%(levelname)s][%(message)s]"

simple_format = "[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d][%(message)s]"

id_simple_format = "[%(levelname)s][%(asctime)s][%(message)s]"

# 设置 log 文件路径
logfile_dir = os.path.dirname(os.path.abspath(__file__))

# 设置 log 文件名
logfile_name = "test.log"

# 如果不存在定义的日志目录就创建一个
if not os.path.isdir(logfile_dir):
    os.mkdir(logfile_dir)

# log配置字典
LOGGING_DIC = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "standard": {
            "format": standard_format
        },
        "simple": {
            "format": simple_format
        }
    },
    "filters": {},
    # 打印到屏幕的日志
    "screen": {
        "level": "DEBUG",
        "class": "logging.StreamHandler",
        "formatter": "simple"
    },
    # 打印到文件的日志,收集 INFO 及以上的日志
    "file":{
        "level": "DEBUG",
        "class": "logging.handlers.RotatingFileHandler",  # 保存到文件
        "formatter": "standard",
        "filename": logfile_path,  # 日志文件
        "maxBytes": 1024*1024*5,  # 日志大小 5M
        "backupCount": 5,
        "encoding": "utf-8",  # 日志文件的编码,不用担心中文乱码的问题
    },
    "loggers": {
        # logging.getLogger(__name__)拿到的logger配置
        "": {
            # 把上面定义的两个handler都加上,即log数据即写入文件又打印到屏幕
            "handlers": ["screen", "file"],
            # 总级别,一定要设置最低的,即 DEBUG
            "level": "DEBUG",
            # 向上(更高level的logger)传递
            "propagate": True,
        },
    },
}

def load_my_logging_cfg():
    # 导入上面定义的logging配置
    logging.config.dictConfig(LOGGING_DIC)
    logger = logging.getLogger("转账业务")
    logger.info("It works!")  # 记录该文件的运行状态

if __name__ == "__main__":
    load_my_logging_cfg()

 

posted @ 2019-01-08 14:49  星满夜空  阅读(353)  评论(0编辑  收藏  举报