1.包的使用
import
第一类: 执行文件用过import导入包以及包的功能
创建一个aaa的包,自行创建一个
__innt__
py文件创建一个tbjx模块发生三件事:
- 将该tbjx文件加载到内存
- 创建一个以tbjx命名的名称空间
- 通过tbjx.的方式引用tbjx模块的所有名字
创建一个包也会发生三件事:
将该aaa包内的
__init__
py文件加载到内存创建一个以aaa命名的名称空间
通过aaa.的方式引用
__init__
的所有名字import aaa # print(aaa.x) # aaa.f1() # print(aaa.m1) # print(aaa.m1.a) # 我想要引用 aaa包的m1文件的a变量 # 错误示例1: import aaa # 1. aaa的 __init__ 里面 写import m1 # 2. print(aaa.m1.a) # print(aaa.m1.a) # 报错原因: No module named 'm1' # 分析报错原因: 模块找不到 内存,内置,sys.path三个地方找不到. # m1 不在内存,不在内置,sys.path 会主动加载执行文件(包的使用.py)的当前目录. # 解决方式: import aaa # 1. 在执行文件写入 import aaa # 2. aaa的 __init__ 里面 写 from aaa import m1 # 3. 然后在执行文件 aaa.m1.a # print(aaa.m1.a) # aaa.m1.func1() import aaa # 如何在当前文件中,引用 aaa包的bbb包. # 1. 在执行文件写入 import aaa # 2. aaa的 __init__ 里面 写 from aaa import bbb # 3. 然后在执行文件 aaa.bbb # print(aaa.bbb) # 如何在当前文件中,引用 aaa包的bbb包 的 变量 name. # 1. 在执行文件写入 import aaa # 2. aaa的 __init__ 里面 写 from aaa import bbb # 3. 然后在执行文件 aaa.bbb # print(aaa.bbb) import aaa # print(aaa.bbb.name) # 如何在当前文件中,引用 aaa包的bbb包 的 mb文件的函数func. # 1. 在执行文件写入 import aaa # 2. 在aaa包的__Init__ 写上 from aaa import bbb (这样写 bbb包的__init__里面所有的名字都能引用) # print(aaa.bbb.name) # 3. 在bbb包的__Init__ 写上 from aaa.bbb import mb # aaa.bbb.mb.func3() # 首先 无论从哪里引用模块,import 或者 from ... import ... # 最开始的模块或者包名一定是内存,内置,sys.path中能找到的.(可参考bbb包中的 __init__) # 直接import 为了让我们会使用 包里面的 __init__
from ... import ...
# from ... import ... # 通过这种方式不用设置__init__文件 # from aaa import m1 # m1.func() # from aaa.bbb.m2 import func1 # func1() # from aaa.bbb import m2 # m2.func1() # from a.b.c import d.e.f # c的. 的前面一定是包 # import 的后面一定是名字,并且不能 再有点 # from aaa.bbb.m2.func1 import a # 错误的 # from aaa.bbb import m2 # m2.func1()
2.日志
low版日志
# import logging # logging.basicConfig( # level=logging.DEBUG, # ) # # logging.debug('debug message') # # logging.info('info message') # # logging.warning('warning message') # # logging.error('error message') # # logging.critical('critical message') # 应用: # def func(): # print('in func') # logging.debug('正常执行') # func() # try: # i = input('请输入选项:') # int(i) # except Exception as e: # logging.error(e) # print(11) # low版的日志:缺点: 文件与屏幕输入只能选择一个. import logging logging.basicConfig( # level=logging.DEBUG, level=30, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', filename=r'test.log', ) # logging.debug('调试模式') # 10 # logging.info('正常模式') # 20 logging.warning('警告信息') # 30 # logging.error('错误信息') # 40 # logging.critical('严重错误信息') # 50
标配版日志
# import logging # # 创建一个logging对象 # logger = logging.getLogger() # # 创建一个文件对象 # fh = logging.FileHandler('标配版.log', encoding='utf-8') # # 创建一个屏幕对象 # sh = logging.StreamHandler() # # 配置显示格式 # formatter1 = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') # formatter2 = logging.Formatter('%(asctime)s %(message)s') # fh.setFormatter(formatter1) # sh.setFormatter(formatter2) # logger.addHandler(fh) # logger.addHandler(sh) # # 总开关 # logger.setLevel(10) # fh.setLevel(10) # sh.setLevel(40) # logging.debug('调试模式') # 10 # logging.info('正常模式') # 20 # logging.warning('警告信息') # 30 # logging.error('错误信息') # 40 # logging.critical('严重错误信息') # 50
旗舰版日志
""" logging配置 """ import logging.config # 定义三种日志输出格式 开始 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' # 定义日志输出格式 结束 logfile_name = 'login.log' # log文件名 logfile_path_staff = r'D:\s23\day19\日志模块\旗舰版日志文件夹\staff.log' logfile_path_boss = r'D:\s23\day19\日志模块\旗舰版日志文件夹\boss.log' # log配置字典 # LOGGING_DIC第一层的所有的键不能改变 LOGGING_DIC = { 'version': 1, # 版本号 'disable_existing_loggers': False, # 固定写法 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, 'id_simple':{ 'format': id_simple_format } }, 'filters': {}, 'handlers': { #打印到终端的日志 'sh': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到屏幕 'formatter': 'id_simple' }, #打印到文件的日志,收集info及以上的日志 'fh': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'standard', 'filename': logfile_path_staff, # 日志文件 'maxBytes': 5000, # 日志大小 5M 'backupCount': 5, 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, 'boss': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'id_simple', 'filename': logfile_path_boss, # 日志文件 'maxBytes': 5000, # 日志大小 5M 'backupCount': 5, 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, }, 'loggers': { #logging.getLogger(__name__)拿到的logger配置 '': { 'handlers': ['sh', 'fh', 'boss'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)传递 }, }, } def md_logger(): logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置 logger = logging.getLogger() # 生成一个log实例 return logger # logger.debug('It works!') # 记录该文件的运行状态 dic = { 'username': '小黑' } def login(): # print('登陆成功') md_logger().info(f"{dic['username']}登陆成功") # def aricle(): # print('欢迎访问文章页面') login() # aricle()
3.包的跨模块引用
当你的模块文件越来越多,就需要对模块文件进行划分,比如把负责跟数据库交互的都放一个文件夹,把与页面交互相关的放一个文件夹,
my_proj/ ├── apeland_web #代码目录 │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── tests.py │ └── views.py ├── manage.py └── my_proj #配置文件目录 ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py
像上面这样,一个文件夹管理多个模块文件,这个文件夹就被称为包
一个包就是一个文件夹,但该文件夹下必须存在 init.py 文件, 该文件的内容可以为空, int.py用于标识当前文件夹是一个包。
这个init.py的文件主要是用来对包进行一些初始化的,当当前这个package被别的程序调用时,init.py文件会先执行,一般为空, 一些你希望只要package被调用就立刻执行的代码可以放在init.py里,一会后面会演示。
跨模块导入
目录结构如下
my_proj ├── apeland_web │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── tests.py │ └── views.py ├── manage.py └── my_proj ├── settings.py ├── urls.py └── wsgi.py
根据上面的结构,如何实现在apelandweb/views.py里导入my
proj/settings.py
模块?直接导入的话,会报错,说找到不模块
是因为路径找不到,my_proj/settings.py 相当于是apeland_web/views.py的父亲(apeland_web)的兄弟(my_proj)的儿子(settings.py),settings.py算是views.py的表弟啦,在views.py里只能导入同级别兄弟模块代码,或者子级别包里的模块,根本不知道表弟表哥的存在。这可怎么办呢?
答案是添加环境变量,把父亲级的路径添加到sys.path中,就可以了,这样导入 就相当于从父亲级开始找模块了。
apeland_web/views.py中添加环境变量
import sys ,osBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #__file__的是打印当前被执行的模块.py文件相对路径,注意是相对路径print(BASE_DIR) # 输出是/Users/alex/PycharmProjects/apeland_py_learn/day4_常用模块/my_proj sys.path.append(BASE_DIR)from my_proj import settingsprint(settings.DATABASES)
官方推荐的跨目录导入方法
虽然通过添加环境变量的方式可以实现跨模块导入,但是官方不推荐这么干,因为这样就需要在每个目录下的每个程序里都写一遍添加环境变量的代码。
官方推荐的玩法是,在项目里创建个入口程序,整个程序调用的开始应该是从入口程序发起,这个入口程序一般放在项目的顶级目录
这样做的好处是,项目中的二级目录 apeland_web/views.py中再调用他表亲my_proj/settings.py时就不用再添加环境变量了。
原因是由于manage.py在顶层,manage.py启动时项目的环境变量路径就会自动变成….xxx/my_proj/这一级别