一、什么是包?


1 #官网解释 2 Packages are a way of structuring Python’s module namespace by using “dotted module names” 3 包是一种通过使用‘.模块名’来组织python模块名称空间的方式。 4 5 #具体的:包就是一个包含有__init__.py文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来 6 7 #需要强调的是: 8 1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错 9 10 2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块
二、为何要使用包
包的本质就是一个文件夹,那么文件夹唯一的功能就是将文件组织起来
随着功能越写越多,我们无法将所以功能都放到一个文件中,于是我们使用模块去组织功能,而随着模块越来越多,我们就需要用文件夹将模块文件组织起来,以此来提高程序的结构性和可维护性
三、关于包使用的注意事项
#1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,
否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
#2、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
#3、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间


1 ############run文件############### 2 # import pack 3 # pack.m1.f1() #pack__init_中from pack import m1\# from pack.m1 import f1 4 # pack.m2.f2() #pack__init_中from pack import m2\# from pack.m2 import f2 5 # 6 # pack.f1() # from pack.m1 import f1 7 # pack.f2() # from pack.m2 import f2 8 9 10 #(2)#直接调用f1\f2 11 # from pack.m1 import f1 12 # f1() 13 # 14 # from pack import m2 15 # m2.f2() 16 # 17 # from pack.m2 import f2 18 # f2() 19 20 #(3)调用pack1f3 21 import pack 22 pack.f3() 23 24 25 #(4) 26 # import pack 27 # pack.f1() 28 第一级__init__下面的代码 29 ''' 30 (1、2)2种方法在run函数中调用顺序先在run中导入pack文件夹---然后(1)是导入到模块名只能用 31 pack.m1.f1()、pack.m2.f2()方法调用函数 32 (2)是导入模块命中的函数 调用方法是pack.f1()、pack.f2() ----pack.m1.f1()、pack.m2.f2()都可以 33 ''' 34 35 #(1) 第一种写法 36 # from pack import m1 37 # from pack import m2 38 39 #(2)第二种写法 40 # from pack.m1 import f1 41 # from pack.m2 import f2 42 43 #(3)调用pack1中的m3 44 # from pack import pack1 ##等于from .import pack1 45 46 #(4)调用pack1中的m3 47 # from pack.pack1.m3 import f3 48 49 from .m1 import f1 50 from .m2 import f2


1 包的使用之from ... import ... 2 3 需要注意的是from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c是错误语法 4 from glance.db import models 5 models.register_models('mysql') 6 7 from glance.db.models import register_models 8 register_models('mysql')


1 我们的最顶级包glance是写给别人用的,然后在glance包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式: 2 3 绝对导入:以glance作为起始 4 5 相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内) 6 7 例如:我们在glance/api/version.py中想要导入glance/cmd/manage.py 8 1 在glance/api/version.py 9 2 10 3 #绝对导入 11 4 from glance.cmd import manage 12 5 manage.main() 13 6 14 7 #相对导入 15 8 from ..cmd import manage 16 9 manage.main()
四、logging日志的使用
(1)、日志级别
CRITICAL = 50 #FATAL = CRITICAL
ERROR = 40
WARNING = 30 #WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0 #不设置
(2)、默认级别为warning,默认打印到终端
import logging
logging.debug('调试debug')
logging.info('消息info')
logging.warning('警告warn')
logging.error('错误error')
logging.critical('严重critical')
'''
WARNING:root:警告warn
ERROR:root:错误error
CRITICAL:root:严重critical
'''
(3)为logging模块指定全局配置,针对所有logger有效,控制打印到文件中


1 可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有 2 filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。 3 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 4 format:指定handler使用的日志显示格式。 5 datefmt:指定日期时间格式。 6 level:设置rootlogger(后边会讲解具体概念)的日志级别 7 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 8 9 10 11 #格式 12 %(name)s:Logger的名字,并非用户名,详细查看 13 14 %(levelno)s:数字形式的日志级别 15 16 %(levelname)s:文本形式的日志级别 17 18 %(pathname)s:调用日志输出函数的模块的完整路径名,可能没有 19 20 %(filename)s:调用日志输出函数的模块的文件名 21 22 %(module)s:调用日志输出函数的模块名 23 24 %(funcName)s:调用日志输出函数的函数名 25 26 %(lineno)d:调用日志输出函数的语句所在的代码行 27 28 %(created)f:当前时间,用UNIX标准的表示时间的浮 点数表示 29 30 %(relativeCreated)d:输出日志信息时的,自Logger创建以 来的毫秒数 31 32 %(asctime)s:字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 33 34 %(thread)d:线程ID。可能没有 35 36 %(threadName)s:线程名。可能没有 37 38 %(process)d:进程ID。可能没有 39 40 %(message)s:用户输出的消息


1 可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有 2 filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。 3 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 4 format:指定handler使用的日志显示格式。 5 datefmt:指定日期时间格式。 6 level:设置rootlogger(后边会讲解具体概念)的日志级别 7 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 8 9 10 11 #格式 12 %(name)s:Logger的名字,并非用户名,详细查看 13 14 %(levelno)s:数字形式的日志级别 15 16 %(levelname)s:文本形式的日志级别 17 18 %(pathname)s:调用日志输出函数的模块的完整路径名,可能没有 19 20 %(filename)s:调用日志输出函数的模块的文件名 21 22 %(module)s:调用日志输出函数的模块名 23 24 %(funcName)s:调用日志输出函数的函数名 25 26 %(lineno)d:调用日志输出函数的语句所在的代码行 27 28 %(created)f:当前时间,用UNIX标准的表示时间的浮 点数表示 29 30 %(relativeCreated)d:输出日志信息时的,自Logger创建以 来的毫秒数 31 32 %(asctime)s:字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 33 34 %(thread)d:线程ID。可能没有 35 36 %(threadName)s:线程名。可能没有 37 38 %(process)d:进程ID。可能没有 39 40 %(message)s:用户输出的消息
(4)、logging模块的Formatter,Handler,Logger,Filter对象


1 #logger:产生日志的对象 2 3 #Filter:过滤日志的对象 4 5 #Handler:接收日志然后控制打印到不同的地方,FileHandler用来打印到文件中,StreamHandler用来打印到终端 6 7 #Formatter对象:可以定制不同的日志格式对象,然后绑定给不同的Handler对象使用,以此来控制不同的Handler的日志格式


1 ''' 2 critical=50 3 error =40 4 warning =30 5 info = 20 6 debug =10 7 ''' 8 9 10 import logging 11 12 #1、logger对象:负责产生日志,然后交给Filter过滤,然后交给不同的Handler输出 13 logger=logging.getLogger(__file__) 14 15 #2、Filter对象:不常用,略 16 17 #3、Handler对象:接收logger传来的日志,然后控制输出 18 h1=logging.FileHandler('t1.log') #打印到文件 19 h2=logging.FileHandler('t2.log') #打印到文件 20 h3=logging.StreamHandler() #打印到终端 21 22 #4、Formatter对象:日志格式 23 formmater1=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 24 datefmt='%Y-%m-%d %H:%M:%S %p',) 25 26 formmater2=logging.Formatter('%(asctime)s : %(message)s', 27 datefmt='%Y-%m-%d %H:%M:%S %p',) 28 29 formmater3=logging.Formatter('%(name)s %(message)s',) 30 31 32 #5、为Handler对象绑定格式 33 h1.setFormatter(formmater1) 34 h2.setFormatter(formmater2) 35 h3.setFormatter(formmater3) 36 37 #6、将Handler添加给logger并设置日志级别 38 logger.addHandler(h1) 39 logger.addHandler(h2) 40 logger.addHandler(h3) 41 logger.setLevel(10) 42 43 #7、测试 44 logger.debug('debug') 45 logger.info('info') 46 logger.warning('warning') 47 logger.error('error') 48 logger.critical('critical')
(5) 、Logger与Handler的级别
logger是第一级过滤,然后才能到handler,我们可以给logger和handler同时设置level,但是需要注意的是


1 Logger is also the first to filter the message based on a level — if you set the logger to INFO, and all handlers to DEBUG, you still won't receive DEBUG messages on handlers — they'll be rejected by the logger itself. If you set logger to DEBUG, but all handlers to INFO, you won't receive any DEBUG messages either — because while the logger says "ok, process this", the handlers reject it (DEBUG < INFO). 2 3 4 5 #验证 6 import logging 7 8 9 form=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 10 datefmt='%Y-%m-%d %H:%M:%S %p',) 11 12 ch=logging.StreamHandler() 13 14 ch.setFormatter(form) 15 # ch.setLevel(10) 16 ch.setLevel(20) 17 18 l1=logging.getLogger('root') 19 # l1.setLevel(20) 20 l1.setLevel(10) 21 l1.addHandler(ch) 22 23 l1.debug('l1 debug') 24 25 重要,重要,重要!!!
(6)logger的继承

(7)应用


1 import logging 2 3 formatter=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 4 datefmt='%Y-%m-%d %H:%M:%S %p',) 5 6 ch=logging.StreamHandler() 7 ch.setFormatter(formatter) 8 9 10 logger1=logging.getLogger('root') 11 logger2=logging.getLogger('root.child1') 12 logger3=logging.getLogger('root.child1.child2') 13 14 15 logger1.addHandler(ch) 16 logger2.addHandler(ch) 17 logger3.addHandler(ch) 18 logger1.setLevel(10) 19 logger2.setLevel(10) 20 logger3.setLevel(10) 21 22 logger1.debug('log1 debug') 23 logger2.debug('log2 debug') 24 logger3.debug('log3 debug') 25 ''' 26 2017-07-28 22:22:05 PM - root - DEBUG -test: log1 debug 27 2017-07-28 22:22:05 PM - root.child1 - DEBUG -test: log2 debug 28 2017-07-28 22:22:05 PM - root.child1 - DEBUG -test: log2 debug 29 2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug 30 2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug 31 2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug 32 '''


1 import logging 2 3 formatter=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 4 datefmt='%Y-%m-%d %H:%M:%S %p',) 5 6 ch=logging.StreamHandler() 7 ch.setFormatter(formatter) 8 9 10 logger1=logging.getLogger('root') 11 logger2=logging.getLogger('root.child1') 12 logger3=logging.getLogger('root.child1.child2') 13 14 15 logger1.addHandler(ch) 16 logger2.addHandler(ch) 17 logger3.addHandler(ch) 18 logger1.setLevel(10) 19 logger2.setLevel(10) 20 logger3.setLevel(10) 21 22 logger1.debug('log1 debug') 23 logger2.debug('log2 debug') 24 logger3.debug('log3 debug') 25 ''' 26 2017-07-28 22:22:05 PM - root - DEBUG -test: log1 debug 27 2017-07-28 22:22:05 PM - root.child1 - DEBUG -test: log2 debug 28 2017-07-28 22:22:05 PM - root.child1 - DEBUG -test: log2 debug 29 2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug 30 2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug 31 2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug 32 '''


1 #logging_config.py 2 LOGGING = { 3 'version': 1, 4 'disable_existing_loggers': False, 5 'formatters': { 6 'standard': { 7 'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' 8 '[%(levelname)s][%(message)s]' 9 }, 10 'simple': { 11 'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' 12 }, 13 'collect': { 14 'format': '%(message)s' 15 } 16 }, 17 'filters': { 18 'require_debug_true': { 19 '()': 'django.utils.log.RequireDebugTrue', 20 }, 21 }, 22 'handlers': { 23 #打印到终端的日志 24 'console': { 25 'level': 'DEBUG', 26 'filters': ['require_debug_true'], 27 'class': 'logging.StreamHandler', 28 'formatter': 'simple' 29 }, 30 #打印到文件的日志,收集info及以上的日志 31 'default': { 32 'level': 'INFO', 33 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切 34 'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"), # 日志文件 35 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 36 'backupCount': 3, 37 'formatter': 'standard', 38 'encoding': 'utf-8', 39 }, 40 #打印到文件的日志:收集错误及以上的日志 41 'error': { 42 'level': 'ERROR', 43 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切 44 'filename': os.path.join(BASE_LOG_DIR, "xxx_err.log"), # 日志文件 45 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 46 'backupCount': 5, 47 'formatter': 'standard', 48 'encoding': 'utf-8', 49 }, 50 #打印到文件的日志 51 'collect': { 52 'level': 'INFO', 53 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切 54 'filename': os.path.join(BASE_LOG_DIR, "xxx_collect.log"), 55 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 56 'backupCount': 5, 57 'formatter': 'collect', 58 'encoding': "utf-8" 59 } 60 }, 61 'loggers': { 62 #logging.getLogger(__name__)拿到的logger配置 63 '': { 64 'handlers': ['default', 'console', 'error'], 65 'level': 'DEBUG', 66 'propagate': True, 67 }, 68 #logging.getLogger('collect')拿到的logger配置 69 'collect': { 70 'handlers': ['console', 'collect'], 71 'level': 'INFO', 72 } 73 }, 74 } 75 76 77 # ----------- 78 # 用法:拿到俩个logger 79 80 logger = logging.getLogger(__name__) #线上正常的日志 81 collect_logger = logging.getLogger("collect") #领导说,需要为领导们单独定制领导们看的日志