python模块和规范开发

模块

1.什么是模块?

一个模块就是一个py文件。

模拟博客园系统作业,100000行代码. 不可能全部存在一个文件.

  1. 不易维护.
  2. 效率低.

分文件: 10个文件.每个文件有50个函数,有一写相同功能或者相似功能的函数.代码冗余,重复性.我们应该将这10个函数提取出来,放在一个文件中,随用随拿.

2.模块的优点

  1. 节省代码.
  2. 容易维护,组织结构更清晰.

一个模块就是一个py文件,这个模块存储很多相似的功能,相似的函数的集合体.

3.模块的分类:

  • 内置模块,标准库.python解释器自带的,time,os,sys,等等.200多种.
  • 第三方库(模块),各种大神写的一些模块,通过pip install....安装.6000种.
  • 自己写的模块.自定义模块.

4.import

# import tbjx
# # 当我引用tbjx模块的时候,实际上将tbjx.py执行一遍,加载到内存.
# import tbjx
# import tbjx
# import tbjx
# import tbjx
# import tbjx

# 只是第一次引用时,将此模块加载到内存.
  1. 执行文件:02 模块import

  2. 被引用文件(模块): tbjx.py

  3. 第一次导入模块发生的三件事

    import tbjx
    n = 1
    # 引用模块发生三件事.
    '''
        1. 将tbjx.py文件加载到内存.
        2. 在内存中创建一个以tbjx命名的名称空间.
        3. 通过tbjx名称空间的名字.等方式引用此模块的名字(变量,函数名,类名等等).
    '''
    
    # print(tbjx.name)
    # tbjx.read1()
    # tbjx.read2()
    
  4. 被导入模块有独立的名称空间

    # 坑:通过tbjx.的方式引用此模块的名字时,一定一定是从此模块中寻找.
    # 通过import 引用模块 他有自己的独立名称空间,与当前执行文件没有关系.
    name = '李业'
    print(tbjx.name)
    
    def read1():
        print('in 02 模块import')
    
    tbjx.read1()
    
  5. 为模块起别名

    起别名:将一个比较长的模块名化简成简单的.
    # import tbjx as cb
    # ##1 书写方便.
    # import tbjx as tb
    # print(tb.name)
    # tb.read1()
    # ##2 简化代码.
    # content = input('>>>').strip()
    # if content == 'mysql':
    #     import mysql_
    #     mysql_.sqlprase()
    # elif content == 'oracle':
    #     import oracle_
    #     oracle_.sqlprase()
    
    # content = input('>>>').strip()
    #
    # if content == 'mysql':
    #     import mysql_ as db
    # elif content == 'oracle':
    #     import oracle_ as db
    #
    # db.sqlprase()  # 统一化接口
    
    
  6. 导入多个模块

     引入多个模块
    # import time,os,sys  # 不推荐.
    import time
    import os
    import sys
    
    # 易于阅读 易于编辑 易于搜索 易于维护。
    

5.from... import...

# from tbjx import name
# from tbjx import read1
# print(globals())
# 相当于从tbjx模块的全局空间中将name,read1变量与值的对应关系
# 复制到当前执行文件的全局名称空间中.
# print(name)#name是复制一份过来
# read1()#是复制了read1的函数内存地址

# 优点:使用起来方便了.
# 缺点:容易与当前执行文件产生覆盖效果.
  1. from... import...的使用

    #from 文件夹 impot 文件名
    #可以用文件名.函数名进行操作
    # 特殊情况:极值情况,工作中不会出现.(了解)
    # 因为如果你要是引用一些模块的变量,那么执行文件中就不应该出现同名变量.
    
  2. from... import...与import对比

  3. 一行导入多个

    # from tbjx import name
    # from tbjx import read1
    
  4. from... import *

    # from ... import *  尽量别单独用
    # from tbjx import *
    # print(name)
    # read1()
    # read2()
    # 1,全部将tbjx的所有名字复制过来,无用功.
    # 2,容易覆盖.
    
    # from ... import * 与__all__配合使用(写在模块文件中)
    

6.py文件的两种功能

  1. py文件的第一个功能:执行文件(承载代码) 脚本.

    直接打印__name__返回__main__

  2. py文件的第二个功能: 模块(被执行文件).

    直接打印__name__返回tbjx 模块名

作用:用来控制.py文件在不同的应用场景下执行不同的逻辑(或者是在模块文件中测试代码)

7.模块的搜索路径

寻找模块的路径: 内存 ----> 内置模块  ---> sys.path中找
# 只要这三个地方:内存 内置模块 sys.path可以找到这个引用的模块的路径,这个模块就可以直接引用到.
# import sys
# # print(sys.path)
# # import tbjx
# print(sys.modules)

# 如何引用到tbjx1.py
import sys
# print(sys.path)
sys.path.append(r'D:s23day15')
# import tbjx
import tbjx1
tbjx1.read1()

序列化模块

序列化:将一个数据结构(list,dict....)转化成一个特殊的序列(特殊的字符串)的过程.

# l1 = [1, 2, 3]
# ret = str(l1)
# print(ret,type(ret))
# print(eval(ret))  # 不让用

# 文件存取时,遇到的矛盾.
# dic ={'username': '太白', 'password': 123}

# dic = {1: {'username': '太白', 'password': 123,'status': False},
#        2:{'username': 'alex', 'password': 123,'status': False}
#        }

# 这个字典能放在全局么?
# with open('register.json',encoding='utf-8',mode='w') as f1:
#     f1.write(str(dic))
# with open('register',encoding='utf-8') as f1:
#     ret = f1.read()
#     print(ret,type(ret))
#
# # 数据结构 --- > str() 存储在文件, 读取出来时,反转不回去.
# # 网络传输.
# l1 = [i for i in range(100000)]
# # 凡是数据通过网络传出去最终的格式必须bytes
# s1 = str(l1)
# b1 = s1.encode('utf-8')
# print(b1)  # b1可以发送出去
#
# s2 = b1.decode('utf-8')
# print(s2,type(s2))
# s2 转化不成列表了.

# 我们现在要解决的问题: 如果有一种特殊的字符串,这个字符串可以与任何的数据结构互相转换.

序列化模块分类:

# 序列化模块: 将一中数据结构转化成特殊的序列(特殊的字符串,bytes)并且还可以反转回去.

    # json模块: 是所有语言公认的一种序列.最最常用的
    #所以支持的python数据结构有限: int str bool dict list(tuple),None,float

    # None  ---> Null ----> NUll
    # dict  --->
    # pickle模块: 只能python语言中使用的,序列化模块:
    # 支持python所有的数据类型以及对象.
    # shevle模块(不讲): 课下了解(只能是文件存取).

json序列化:

两对四个方法:

dumps,loads 主要用于网络传输,可以用于文件的存取.

import json
# dumps,loads 主要用于网络传输,可以用于文件的存取.
# dic = {'username': '太白', 'password': 123,'status': False}
# ret = json.dumps(dic)
# # print(ret,type(ret))

# ret_dict = json.loads(ret)
# print(ret_dict)

# 特殊的参数
# dic = {'username': '太白', 'password': 123,'status': False}
# # print(dic)
# ret = json.dumps(dic,ensure_ascii=False,sort_keys=True)
# print(ret,type(ret))
# import json
# dic = {'username': '太白', 'password': 123,'status': False}
# s_dict = json.dumps(dic)
# with open('jsonlx.json',encoding='utf-8',mode='w') as f1:
#     f1.write(s_dict)
#
# with open('jsonlx.json',encoding='utf-8') as f2:
#     content = f2.read()
#     print(json.loads(content))

多个数据如何存储到一个文件中?

import json
# dic1 = {'username': '太白', 'password': 123,'status': False}
# dic2 = {'username': 'alex', 'password': 123,'status': False}
# dic3 = {'username': 'ly', 'password': 123,'status': False}
# with open('jsonmore.json',encoding='utf-8',mode='a') as f1:
#     f1.write(f'{json.dumps(dic1)}
{json.dumps(dic2)}
{json.dumps(dic3)}')

# with open('jsonmore.json',encoding='utf-8') as f1:
#     for line in f1:
#         ret = json.loads(line)
#         print(ret,type(ret))

pickle序列化:python专用

pickle序列化:

dumps,loads 只能是网络传输

import pickle

# dumps,loads  只能是网络传输
# l1 = ['wusir', '太白', '小黑', 666]
# ret = pickle.dumps(l1)
# # print(ret)
#
# l2 = pickle.loads(ret)
# print(l2,type(l2))
dump load 数据结构存取文件.

import pickle
# l1 = ['wusir', '太白', '小黑', 666]
# with open('pickle练习.pickle',mode='wb') as f1:
#     pickle.dump(l1,f1)

# with open('pickle练习.pickle', mode='rb') as f1:
#     ret = pickle.load(f1)
#     print(ret,type(ret))

# 多个数据写入文件
l1 = ['wusir', '太白', '小黑1', 666]
l2 = ['wusir', '太白', '小黑2', 666]
l3 = ['wusir', '太白', '小黑3', 666]
# with open('pickle练习1.pickle',mode='wb') as f1:
# #     pickle.dump(l1,f1)
# #     pickle.dump(l2,f1)
# #     pickle.dump(l3,f1)
#
# with open('pickle练习1.pickle', mode='rb') as f1:
#     ret1 = pickle.load(f1)
#     ret2 = pickle.load(f1)
#     ret3 = pickle.load(f1)
#     print(ret1,ret2,ret3)

os模块

# 目录: 文件夹.
# 工作目录,当前目录,父级目录: day17

import os
# print(os.getcwd())  # D:s23day17 绝对路径  ***
# os.chdir(r'D:s23day9')
# print(os.getcwd())
# print(os.curdir)
# print(os.pardir)

# 和文件夹相关  ***
import os
# os.makedirs('dirname1/dirname2/dirname3/dirname4')  # 多级目录
# os.removedirs('dirname1/dirname2/dirname3/dirname4') # 截止到有文件的那层
# os.mkdir(r'd:abc') # 单级目录
# os.rmdir('abc')
# print(os.listdir(r'D:s23day15'))

#
# os.remove()  删除一个文件  ***
# os.rename("oldname","newname")  重命名文件/目录  ***
# print(os.stat(r'D:s23day171 昨日内容回顾.py'))

# path 和路径相关  ***
# print(os.path.abspath('04 os模块.py'))  # D:s23day171 昨日内容回顾.py
# print(os.path.split(os.path.abspath('01 昨日内容回顾.py')))  # ('D:\s23\day17', '01 昨日内容回顾.py')
# print(os.path.dirname(r'D:s23day91 初始函数.py'))  # 获取父级目录
# print(os.path.dirname(os.path.abspath('01 昨日内容回顾.py')))
# print(__file__)  # 动态获取当前文件的绝对路径
# 获取当前文件的爷爷级的目录
# print(os.path.dirname(os.path.dirname(__file__)))
# print(os.path.basename(r'D:s23day91 初始函数.py'))  # 获取文件名
# print(os.path.exists(r'D:s23day92 初始函数.py'))
# 判断是否是绝对路径
# print(os.path.isabs(r'D:s23day91 初始函数.py'))
# print(os.path.isabs(r'day17/01 昨日内容回顾.py'))
# 判断该路径是否是一个文件路径
# print(os.path.isfile(r'D:s23day91 初始函数.py'))
# print(os.path.isfile(r'D:s23day9'))
# print(os.path.isdir(r'D:s23day17dirname1dirname2'))
# print(os.path.exists(r'D:s23day17dirname1dirname2'))
# 判断是否是一个目录(文件夹)
# print(os.path.isdir(r'D:s23day172 序列化模块.py'))
# D:s23day16评论文章
# path = os.path.join('D:','s23','day20','随便')
# print(path)
# par_dir = os.path.dirname(__file__)
# print(par_dir)  # D:/s23/day17
# path = r'D:s23day17dblydata'
# path = par_dir + 'db' +'lydata'
# path = os.path.join(par_dir,'db','lydata')
# with open(path,encoding='utf-8',mode='a') as f1:
#     f1.write('李业在红浪漫消费998元')

# print(os.path.getatime('D:s23day17dblydata'))
# print(os.path.getmtime('D:s23day17dblydata'))
# print(os.path.getsize('D:s23day17dblydata'))

# print(os.stat(r'D:s23day171 昨日内容回顾.py'))

sys模块

import sys
# sys.path  ***
# print(sys.version)  # 版本

# for i in range(3):
#     print(i)
# # exit()  # 强制退出
# # quit()
# for i in range(5):
#     print(i)

# print(sys.platform)

hashlib模块

加密模块, 摘要算法,散列算法,等等.它是一堆加密算法的集合.

liye|zmdsb

太白|123

明文形式存储的,带来安全隐患.

hashlib如何加密?

  1. 将一个bytes类型的数据 通过hashlib进行加密返回 一个等长度的16进制数字.
  2. 过程不可逆.
  3. 相同的bytes类型的数据通过相同的加密方法得到的数字绝对相同.
  4. 不相同的bytes类型的数据通过相同的加密方法得到的数字绝对不相同.

撞库: 111111, 123456, 000000,19980123,

{'202cb962ac59075b964b07152d234b70': 123456}

hashlib 的用途:

  1. 密码加密.
  2. 文件一致性校验.

密码加密:

# 密码加密
# md5
# ret = hashlib.md5()
# ret.update('123'.encode('utf-8'))
# s = ret.hexdigest()
# print(s,type(s))



# 撞库

# ret = hashlib.md5()
# ret.update('123456*@qwe'.encode('utf-8'))
# s = ret.hexdigest()
# print(s,type(s))

# 加固定盐
# ret = hashlib.md5('xxx教育'.encode('utf-8'))
# ret.update('123456'.encode('utf-8'))
# s = ret.hexdigest()
# print(s,type(s))

# 加动态的盐
# username = input('输入用户名:').strip()
# password = input('输入密码').strip()
# ret = hashlib.md5(username[::2].encode('utf-8'))
# ret.update(password.encode('utf-8'))
# s = ret.hexdigest()
# print(s)

# sha系列: 安全系数高,耗时高.
# 加盐,加动态盐
# ret = hashlib.sha512()
# ret.update('123456fdklsajflsdfjsdlkafjafkl'.encode('utf-8'))
# s = ret.hexdigest()
# print(s,type(s))
#

文件的一致性校验:

# low版
# import hashlib
# ret = hashlib.md5()
# with open('MD5文件校验',mode='rb') as f1:
#     content = f1.read()
#     ret.update(content)
# print(ret.hexdigest())
#


# 分步update
# s1 = '老男孩教育 最好的python 讲师 是 太白'
#
# ret = hashlib.md5()
# ret.update('老男孩教育'.encode('utf-8'))
# ret.update(' 最好的python'.encode('utf-8'))
# ret.update(' 讲师 是'.encode('utf-8'))
# ret.update(' 太白'.encode('utf-8'))
# print(ret.hexdigest())  # 90c56d265a363292ec70c7074798c913



# 高达上版,也可以用for
import hashlib
def md5_file(path):
    ret = hashlib.md5()
    with open(path,mode='rb') as f1:
        while 1:
            content = f1.read(1024)
            if content:
                ret.update(content)
            else:
                return ret.hexdigest()


print(md5_file(r'D:s23day17python-3.7.4rc1-embed-win32.zip'))

规范开发

conf文件夹:

settings.py:

配置文件,就是放置一些项目中需要的静态参数,比如文件路径,数据库配置,软件的默认设置等等

lib文件夹:

common.py:

公共组件文件,这里面放置一些我们常用的公共组件函数,并不是我们核心逻辑的函数,而更像是服务于整个程序中的公用的插件,程序中需要即调用。比如我们程序中的装饰器auth,有些函数是需要这个装饰器认证的,但是有一些是不需要这个装饰器认证的,它既是何处需要何处调用即可。比如还有密码加密功能,序列化功能,日志功能等这些功能都可以放在这里。

core文件夹:

src.py:

这个文件主要存放的就是核心逻辑功能,你看你需要进行选择的这些核心功能函数,都应该放在这个文件中。

bin文件夹:

start.py:

项目启动文件。你的项目需要有专门的文件启动,而不是在你的核心逻辑部分进行启动的

db文件夹

register:

这个文件文件名不固定,register只是我们项目中用到的注册表,但是这种文件就是存储数据的文件,类似于文本数据库,那么我们一些项目中的数据有的是从数据库中获取的,有些数据就是这种文本数据库中获取的,总之,你的项目中有时会遇到将一些数据存储在文件中,与程序交互的情况,所以我们要单独设置这样的文件。

log文件夹:

access.log

log文件顾名思义就是存储log日志的文件。日志我们一会就会讲到,日志主要是供开发人员使用。比如你项目中出现一些bug问题,比如开发人员对服务器做的一些操作都会记录到日志中,以便开发者浏览,查询。

README

说明文件

time模块

与时间相关的模块:

三种形式:

  1. 时间戳(timestamp) :通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型

  2. 人类看得懂的时间,格式化时间. 2019-6-28 12:00

  3. 结构化时间: python语言使用的,解释器使用的

    元组(struct_time) :struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天等)

# print(time.time())当前的时间戳
# 格式化时间:
# 字符串类型
# print(time.strftime("%Y-%m-%d %H:%M:%S"))
# print(time.strftime("%y-%m-%d %H:%M:%S  %A"))
# ret = time.strftime("%Y{}%m{}%d{} %H:%M:%S")
# print(ret)
# print(ret.format('年','月','日'))
#结构化时间
# print(time.localtime())


# 时间戳 转化成 格式化时间
# timestamp = time.time()当前时间戳
# st = time.localtime(timestamp)时间戳转结构化时间
# # print(st)
# ft = time.strftime("%y-%m-%d %H:%M:%S",st)结构化时间转格式化时间
# print(ft)


# 格式化时间转化成时间戳
# ft = time.strftime("%y-%m-%d %H:%M:%S")当前格式化的时间
# # print(ft)
# st = time.strptime(ft,"%y-%m-%d %H:%M:%S")格式化时间转结构化时间
# # print(st)
# timestamp = time.mktime(st)结构化时间转时间戳
# print(timestamp)

random模块

import random
# print(random.random())  # 大于0且小于1之间的小数
# print(random.uniform(1, 6))  # ***

# print(random.randint(1,5))  # 1    5 可以取到  ***
# print(random.randrange(1,10,2))  # 顾头不顾尾  ***

# print(random.choice(['如花', '凤姐', '石榴姐', 1]))  # ***
# print(random.sample(('如花', '凤姐', '石榴姐'), 3))  # 可以控制元素个数  ***

# 打乱顺序
# item = [i for i in range(10)]
# random.shuffle(item)
# print(item)

datatime模块

import datetime
# from datetime import datetime
# time_now = datetime.datetime.now()
# print(str(time_now), type(time_now))
#
# print(datetime.datetime.now() + datetime.timedelta(weeks=3))三周后
# print(datetime.datetime.now() + datetime.timedelta(weeks=-4))四周前
# print(datetime.datetime.now() + datetime.timedelta(days=-15))15天前

# current_time = datetime.datetime.now()
# print(current_time.replace(year=1979))1979年的现在
# print(current_time.replace(year=1989,month=4,day=25))1989年四月25日的这个时间

# print(datetime.date.fromtimestamp(4332543543))这个时间戳的格式化时间

包的使用

# 创建一个包,也会发生三件事:

    1. 将该aaa包内 __init__py文件加载到内存.
    2. 创建一个以aaa命名的名称空间.
    3. 通过aaa. 的方式引用__init__的所有的名字.


      time模块 一个py文件,200个函数,功能特别多,分文件,分三个文件,time文件夹: time1 time2 time3py文件,这个time文件夹就叫做包.

      1. import
      2. from ... import ...
      3. 相对导入与绝对导入


  1. # 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 的后面一定是名字,并且不能 再有点
    

logging 日志

工作日志分四个大类:

  1. 系统日志:记录服务器的一些重要信息:监控系统,cpu温度,网卡流量,重要的硬件的一些指标,运维人员经常使用的,运维人员,记录操作的一些指令.

  2. 网站日志: 访问异常,卡顿,网站一些板块,受欢迎程度,访问量,点击率.等等,蜘蛛爬取次数等等.

  3. 辅助开发日志: 开发人员在开发项目中,利用日志进行排错,排除一些避免不了的错误(记录),辅助开发.

  4. 记录用户信息日志: 用户的消费习惯,新闻偏好,等等.(数据库解决)

    日志: 是谁使用的? 一般都是开发者使用的.

    三个版本:

  5. Low版(简易版).

    import logging
    logging.basicConfig(
        # level=logging.DEBUG
        level=10,
        format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
        # filename=r'test.log',写入文件文件名
    )
    logging.debug("调试")
    logging.info("正常")
    logging.warning("警告")
    logging.error("报错")
    logging.critical("严重跑路")
    
    
  6. 标配版(标准版)

    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 %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
    fh.setFormatter(formatter1)
    sh.setFormatter(formatter2)
    logger.addHandler(fh)
    logger.addHandler(sh)
    #总开关
    logger.setLevel(10)
    
    fh.setLevel(10)
    sh.setLevel(10)
    
    logging.debug("调试")
    logging.info("正常")
    logging.warning("警告")
    logging.error("报错")
    logging.critical("严重跑路")
    
  7. 旗舰版(项目中使用的,Django项目) ***

    1. 自定制(通过字典的方式)日志
    2. 轮转日志的功能.
    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:s23day19日志模块旗舰版日志文件夹staff.log'
    logfile_path_boss = r'D:s23day19日志模块旗舰版日志文件夹oss.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()
    

re模块(正则)

import re
# re.findall()
# 正则表达式: 从一大堆字符串中,找出你想要的字符串.
# 在于对你想要得这个字符串进行一个精确地描述.

# s1 = 'fdsa太白金星'
# print(s1.find('白'))

# 单个字符匹配
# W与w
# w 数字字母下划线中文
# W 非数字字母下划线中文
# print(re.findall('w', '太白jx 12*() _'))
# print(re.findall('W', '太白jx 12*() _'))

# s  匹配的 空格 	 

# S  匹配的 非空格 	 

# print(re.findall('s','太白barry*(_ 	 
'))
# print(re.findall('S','太白barry*(_ 	 
'))

# d 匹配所有的数字
# D 非匹配所有的数字
# print(re.findall('dd','1234567890 alex *(_'))
# print(re.findall('D','1234567890 alex *(_'))

# A ^从开头开始匹配
# print(re.findall('Ahello','hello hello 太白 hell'))
# print(re.findall('^hello','hello hello 太白 hell'))

# ,从结尾开始匹配
# z,有一点问题
# $从结尾开始匹配
# print(re.findall('fjkdsla太白金星','fjkdsla太白金星'))
# print(re.findall('金星$','fjkdsla太白金星'))

# 
 	
# print(re.findall('
','fdsak
 fkjdlas
 	'))
# print(re.findall('	','fdsak
 fkjdlas
 	'))

# 元字符匹配

# . ? * + {m,n} .* .*?
#  . 匹配任意一个字符
# 如果匹配成功光标则移到匹配成功的最后的字符
# 如果匹配未成功光标则向下移动一位再次匹配
# print(re.findall('a.b','aaabbb'))

# ? 匹配0个或者1个由左边字符定义的片段。
# print(re.findall('a?b', 'ab aab'))
# print(re.findall('a?b', 'sb ab aabb'))

#* 匹配0个或者多个左边字符表达式。 满足贪婪匹配
# print(re.findall('a*b','aaab ab b'))
# # print(re.findall('a*b','aasab ab b'))

# + 匹配1个或者多个左边字符表达式。 满足贪婪匹配
# print(re.findall('a+b','aaab ab b'))

# {m,n}  匹配m个至n(n能取到)个左边字符表达式。 满足贪婪匹配
# print(re.findall('a{1,5}b', 'ab aab aaab aaaab aaaaaab aaaaabb'))

# .* 贪婪匹配 从头到尾.
# print(re.findall('a.*b','aab abbliye aaab abbb aa#b'))
# print(re.findall('a.*b','asb abbliyeaaab 
abbb aa#y',re.DOTALL))  # a...................b

# .*? 此时的?不是对左边的字符进行0次或者1次的匹配,
# 而只是针对.*这种贪婪匹配的模式进行一种限定:告知他要遵从非贪婪匹配 推荐使用!
# 0个或者多个
# print(re.findall('a.*?b','ab a#bbbbbb aaab'))
# print(re.findall('a.*b','a#bbbbbb'))
# print(re.findall('a.*?b','a#bbbbbb'))


# []

# print(re.findall('a[abc]b', 'aab abb acb adb afb a_b'))
# print(re.findall('a[abc][bd]b', 'aabb aaabc abd acdbb'))

# print(re.findall('a[0-9]b', 'a1b a3b aeb a*b arb a_b'))

# print(re.findall('a[a-z]b', 'a1b a3b aeb a*b arb a_b'))
# print(re.findall('a[A-Z]b', 'aAb a3b aEb a*b aRb a_b'))
# print(re.findall('a[a-zA-Z]b', 'aab a3b aAb a*b aTb a_b'))
# 当你想匹配 - 时,要把它放在[]里面的最前面或者最后面
# print(re.findall('a[-*$]b', 'a-b a$b a)b a*b '))
# ^ 在中括号里面最前面代表取反
# print(re.findall('a[0-9]b', 'a1b a$b a5b a*b '))
# print(re.findall('a[*^)]b', 'a^b a$b a5b a*b '))

# 'alex_sb wusir_sb ritian_sb 太白_nb yuanbao_sb'
s = 'alex_sb wusir_sb ritian_sb 太白_nb yuanbao_sb dsb_sb'
# print(re.findall('w+_sb',s))
# # 'alex_sb wusir_sb ritian_sb 太白_nb yuanbao_sb'
# # ()
# print(re.findall('(w+)_sb',s))

# |
# print(re.findall('alex|太白|wusir', 'alex太白wusiraleeeex太太白odlb'))



# # () 分组里面加了?: 将全部的内容给我返回回来,而不是将组内的内容返回
# print(re.findall('companies|company',
#                  'Too many companies have gone bankrupt, and the next one is my company'))  # ['ies', 'y']

# printy companies have gone bankrupt, and the next one is my company'))(re.findall('compan(?:ies|y)',
# #                  'Too man


# search match
import re
# 找到第一个符合条件的字符串就返回,返回一个对象,通过对象.group()
# ret = re.search('sb|alex', 'alex sb sb barry 日天')
# ret = re.search('alex', 'fdsjkfd fjdsklalex gfdlgjfdlgjfggfjlgjfkdl')
# # # print(ret)
# # # print(ret.group())
#
# # 从字符串开头匹配,如果以符合条件的字符串开头则返回,否则返回None
# ret = re.match('alex', 'alexfdskfd fjdsklalex gfdlgjfdlgjfggfjlgjfkdl')
# print(ret)
# print(ret.group())

# split
# s1 = 'alex;wusir,太白 吴超~宝元'
# import re
# print(re.split('[;, ~]',s1))
import re
# print(re.sub('barry', '太白', 'barry是最好的讲师,barry就是一个普通老师,请不要将barry当男神对待。'))

# obj = re.compile('d{2}')
# # print(obj.search('fdsa12fds435454').group())
# print(obj.findall('fjdskalf2134fkjsd3245fdjsl545'))

# finditer
ret = re.finditer('d','54fjdkls4535lsdfj6776')
# print(ret)
# print(next(ret))
# print(next(ret).group())
# print(next(ret).group())
# for i in ret:
#     print(i.group())
# print(list(ret))
s1 = '''
时间就是f4321995-04-27,2005-04-27
1999-04-27 老男孩教育创始人
老男孩老师 alex 1980-04-27:1980-04-27
2018-12-08
'''
# print(re.findall('d{4}-d{2}-d{2}',s1))

#
# 匹配一个qq账号 10000开始 第一个元素规定就是非零数字,后面的是随意的数字长度大于5位.
s2 = '56546326546757'
print(re.findall('[1-9][0-9]{4,}',s2))
原文地址:https://www.cnblogs.com/nieice/p/11158008.html