01 模块的基本导入
spam.py
# spam.py print('from the spam.py') __all__ = ['money', 'read1', 'read2'] money = 1000 def read1(): print('spam模块read1:', money) def read2(): print('spam模块read2: ') read1() def change(): global money money = 0
模块笔记.py
""" 1、什么是模块 模块是一系列功能的集合体 模块有4种形式 1、一个py文件就是一个模块 2、一个包含有__init__.py文件的文件夹也是一个模块,称之为包 3、已被编译为共享库或DLL的C或C++扩展 4、使用C编写并链接到python解释器的内置模块 模块有三种来源: 1、python自带的 2、第三方的 3、自定义 2、为何要用模块 1、拿来主义,提升开发效率 2、把自己程序中各部分组件要重复使用的功能放到一个模块中,然后通过导入的方式使用 可以达到减少代码冗余 3、如何用模块 #===================================import导入========================= x = 111 import spam # 文件名叫spam.py,模块名叫spam # 首次导入模块发生的事情 # 1、创建一个模块的名称空间 # 2、运行模块文件内的代码,然后将运行过程中产生的名字都丢到模块的名称空间中 # 3、在当前名称空间中产生一个名字spam,该名字指向模块的名称空间 # 之后的导入都是在直接引用内存中已经创造好的模块空间,不会重复执行文件、重复创建名称空间 # import spam # import spam # import spam # import spam # import spam money = 2000 # print(money) # print(spam.money) # print(spam.read1) # print(spam.read2) # print(spam.change) # spam.read1() # def read1(): # print('====>') # spam.read2() spam.change() print(money) print(spam.money) # 在一行导入多个模块 import os import time import subprocess # 为导入的模块起别名 import configparser as cg # cg.x # cg.y # cg.z # ps:import导入的名字要作为前缀 """ #===================================from...import导入========================= # x=111 # from spam import money,read1,change # 首次导入模块发生3件的事情 # 1、创建一个模块的名称空间 # 2、运行模块文件内的代码,然后将运行过程中产生的名字都丢到模块的名称空间中 # 3、在当前名称空间中产生一个名字money,该名字指向模块的名称空间对应的名字 # money = 2000 # print(money) # read1=11111111 # print(read1) # money=111111111111111111111 # read1() # def change(): # print(money) # change() # print(money) # read1() # from spam import money,read1,change # from spam import money,read1,change # from spam import money,read1,change # from spam import money as m,read1 as r,change as c # from spam import money as m # from spam import read1 as r # from spam import change as c # print(m) # print(r) # print(c) # import spam as sm # spam=123123123 # from spam import money as m # money=1231 # print(money) # print(m) from spam import * # print(money) # print(read1) # print(read2) print(change) # from socket import *
02 循环导入问题
m1.py
print('正在导入m1') def f1(): from m2 import y,f2 print(y) f2() x='m1'
m2.py
print('正在导入m2') def f2(): from m1 import x print(x) y='m2'
run.py
import m1 m1.f1()
03 区分一个py文件的两种用途
run.py
import spam
spam.py
def f1(): print('from f1') def f2(): print('from f2') # print(__name__) # if __name__ == "__main__": # 被当做程序执行 # f1() # f2() # else: # 文件被当做模块导入要执行的代码 # pass if __name__ == '__main__': pass
ATM基本架构
bin
---start.py
conf
---setting.py
core
---src.py
db
---db.txt
---dbhandler.py
lib
---common.py
log
---log.txt
---run.log
README.md
04模块的搜素路径
# 导模块会有以下搜索路径,优先级从高到低 #1、内存中 #2、内置的模块 #3、去环境变量PATH:sys.PATH # ps:sys.PATH的第一个路径是执行文件所在的文件夹 # import sys # print(sys.path) # for item in sys.path: # print(item) # import spam # spam.f1() # # import time # time.sleep(15) # # import spam # spam.f1() # import time # time.sleep(5) # import spam # import aaa.bbb.spam as abs # aaa.bbb.spam.f1() # abs.f1() # from aaa.bbb import spam # spam.f1() import sys # sys.path.append(r"D:weekend_s7day02aaabb") # import spam # spam.f1() sys.path.append(r"D:weekend_s7day02aaa") # import bbb.spam # bbb.spam.f1() # from bbb import spam # spam.f1()
05 序列化模块
""" 1、什么是序列化 把内存中的数据类型转换成一个专门的格式 # 序列化 内存中的数据类型------------>json格式=============》json格式的字符串 内存中的数据类型------------>pickle格式格式========》pickle格式的bytes # 反序列化 内存中的数据类型<------------<json格式=============<json格式的字符串 内存中的数据类型<-----------<pickle格式格式========<pickle格式的bytes json VS pickle json格式能够被所有编程语言识别,不能序列化所有的python数据类型 pickle格式只能被python识别,但是它能序列化所有python数据类型 2、为何要序列化 1、数据的持久化=>存档 json pickle 2、跨平台数据交互=》json 3、如何序列化 序列化 dumps dump 反序列化 loads load """ import json # 序列化 # dic={'name':'egon','age':23.0,'sex':None,'is_ok':True} # res=json.dumps(dic) # res=json.dumps({1,2,3,45}) # json不识别集合类型 # print(res,type(res)) # with open('a.json',mode='wt',encoding='utf-8') as f: # f.write(res) # 反序列化 # with open('a.json',mode='rt',encoding='utf-8') as f: # data_json=f.read() # dic=json.loads(data_json) # print(dic["name"]) # =================》ps: dump与load # 序列化 # dic={'name':'egon','age':23.0,'sex':None,'is_ok':True} # # with open('a.json',mode='wt',encoding='utf-8') as f: # json.dump(dic,f) # 反序列化 # with open('a.json',mode='rt',encoding='utf-8') as f: # dic=json.load(f) # print(dic,type(dic)) # import pickle # # 序列化 # # dic={'name':'egon','age':23.0,'sex':None,'is_ok':True} # # # # res=pickle.dumps(dic) # # # res=pickle.dumps({1,2,3,45}) # pickle可以识别所有python类型 # # print(res,type(res)) # # # # with open('a.pkl',mode='wb') as f: # # f.write(res) # # # 反序列化 # with open('a.pkl',mode='rb') as f: # data_pkl=f.read() # # dic=pickle.loads(data_pkl) # print(dic["name"]) import ujson import json json.dumps=ujson.dumps json.loads=ujson.loads
06 日志模块
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 '''
可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有 filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 format:指定handler使用的日志显示格式。 datefmt:指定日期时间格式。 level:设置rootlogger(后边会讲解具体概念)的日志级别 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 #格式 %(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:用户输出的消息 logging.basicConfig()
#logger:产生日志的对象 #Filter:过滤日志的对象 #Handler:接收日志然后控制打印到不同的地方,FileHandler用来打印到文件中,StreamHandler用来打印到终端 #Formatter对象:可以定制不同的日志格式对象,然后绑定给不同的Handler对象使用,以此来控制不同的Handler的日志格式 ''' critical=50 error =40 warning =30 info = 20 debug =10 ''' import logging #1、logger对象:负责产生日志,然后交给Filter过滤,然后交给不同的Handler输出 logger=logging.getLogger(__file__) #2、Filter对象:不常用,略 #3、Handler对象:接收logger传来的日志,然后控制输出 h1=logging.FileHandler('t1.log') #打印到文件 h2=logging.FileHandler('t2.log') #打印到文件 h3=logging.StreamHandler() #打印到终端 #4、Formatter对象:日志格式 formmater1=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p',) formmater2=logging.Formatter('%(asctime)s : %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p',) formmater3=logging.Formatter('%(name)s %(message)s',) #5、为Handler对象绑定格式 h1.setFormatter(formmater1) h2.setFormatter(formmater2) h3.setFormatter(formmater3) #6、将Handler添加给logger并设置日志级别 logger.addHandler(h1) logger.addHandler(h2) logger.addHandler(h3) logger.setLevel(10) #7、测试 logger.debug('debug') logger.info('info') logger.warning('warning') logger.error('error') logger.critical('critical')
logger是第一级过滤,然后才能到handler,我们可以给logger和handler同时设置level,但是需要注意的是 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). #验证 import logging form=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p',) ch=logging.StreamHandler() ch.setFormatter(form) # ch.setLevel(10) ch.setLevel(20) l1=logging.getLogger('root') # l1.setLevel(20) l1.setLevel(10) l1.addHandler(ch) l1.debug('l1 debug')
import logging formatter=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p',) ch=logging.StreamHandler() ch.setFormatter(formatter) logger1=logging.getLogger('root') logger2=logging.getLogger('root.child1') logger3=logging.getLogger('root.child1.child2') logger1.addHandler(ch) logger2.addHandler(ch) logger3.addHandler(ch) logger1.setLevel(10) logger2.setLevel(10) logger3.setLevel(10) logger1.debug('log1 debug') logger2.debug('log2 debug') logger3.debug('log3 debug') ''' 2017-07-28 22:22:05 PM - root - DEBUG -test: log1 debug 2017-07-28 22:22:05 PM - root.child1 - DEBUG -test: log2 debug 2017-07-28 22:22:05 PM - root.child1 - DEBUG -test: log2 debug 2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug 2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug 2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug '''
""" logging配置 """ 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]' #其中name为getlogger指定的名字 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' # 定义日志输出格式 结束 logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录 logfile_name = 'all2.log' # log文件名 # 如果不存在定义的日志目录就创建一个 if not os.path.isdir(logfile_dir): os.mkdir(logfile_dir) # log文件的全路径 logfile_path = os.path.join(logfile_dir, logfile_name) # log配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, }, 'filters': {}, 'handlers': { #打印到终端的日志 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到屏幕 'formatter': 'simple' }, #打印到文件的日志,收集info及以上的日志 'default': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'standard', 'filename': logfile_path, # 日志文件 'maxBytes': 1024*1024*5, # 日志大小 5M 'backupCount': 5, 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, }, 'loggers': { #logging.getLogger(__name__)拿到的logger配置 '': { 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)传递 }, }, } def load_my_logging_cfg(): logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置 logger = logging.getLogger(__name__) # 生成一个log实例 logger.info('It works!') # 记录该文件的运行状态 if __name__ == '__main__': load_my_logging_cfg() logging配置文件
import logging # 一:日志配置 logging.basicConfig( # 1、日志输出位置:1、终端 2、文件 # filename='access.log', # 不指定,默认打印到终端 # 2、日志格式 format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', # 3、时间格式 datefmt='%Y-%m-%d %H:%M:%S %p', # 4、日志级别 # critical => 50 # error => 40 # warning => 30 # info => 20 # debug => 10 level=30, ) # 二:输出日志 logging.debug('调试debug') logging.info('消息info') logging.warning('警告warn') logging.error('错误error') logging.critical('严重critical') ''' # 注意下面的root是默认的日志名字 WARNING:root:警告warn ERROR:root:错误error CRITICAL:root:严重critical '''
""" logging配置 """ import os # 1、定义三种日志输出格式,日志中可能用到的格式化串如下 # %(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用户输出的消息 # 2、强调:其中的%(name)s为getlogger时指定的名字 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' test_format = '%(asctime)s] %(message)s' # 3、日志配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, 'test': { 'format': test_format }, }, 'filters': {}, 'handlers': { #打印到终端的日志 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到屏幕 'formatter': 'simple' }, #打印到文件的日志,收集info及以上的日志 'default': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,日志轮转 'formatter': 'standard', # 可以定制日志文件路径 # BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # log文件的目录 # LOG_PATH = os.path.join(BASE_DIR,'a1.log') 'filename': 'a1.log', # 日志文件 'maxBytes': 1024*1024*5, # 日志大小 5M 'backupCount': 5, 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, 'other': { 'level': 'DEBUG', 'class': 'logging.FileHandler', # 保存到文件 'formatter': 'test', 'filename': 'a2.log', 'encoding': 'utf-8', }, }, 'loggers': { #logging.getLogger(__name__)拿到的logger配置 '': { 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制) 'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递 }, '专门的采集': { 'handlers': ['other',], 'level': 'DEBUG', 'propagate': False, }, }, } 日志配置字典LOGGING_DIC
import settings # !!!强调!!! # 1、logging是一个包,需要使用其下的config、getLogger,可以如下导入 # from logging import config # from logging import getLogger # 2、也可以使用如下导入 import logging.config # 这样连同logging.getLogger都一起导入了,然后使用前缀logging.config. # 3、加载配置 logging.config.dictConfig(settings.LOGGING_DIC) # 4、输出日志 logger1=logging.getLogger('用户交易') logger1.info('egon儿子alex转账3亿冥币') # logger2=logging.getLogger('专门的采集') # 名字传入的必须是'专门的采集',与LOGGING_DIC中的配置唯一对应 # logger2.debug('专门采集的日志') common.py