re模块
在python要想使用正则必须借助于模块,re就是其中之一
''' 基本操作方法 '''
import re
re.findall('正则表达式', '带匹配的文本') # 根据正则匹配除所有符合条件的数据
res = re.findall('a', 'eva chick jason')
print(res) # ['a', 'a'] 结果是一个列表(要么有元素,要么空列表)
res = re.search('正则表达式', '带匹配的文本') # 根据正则匹配到一个符合条件的就结束
res = re.search('a', 'eva chick jason')
print(res) # 结果对象 <_sre.SRE_Match object; span=(2, 3), match='a'>
print(res.group()) # 正在的结果 a
""" 如果没有符合条件的数据 那么search返回None 并且使用group会直接报错"""
使用group不报错解决方案:
if res:
print(res.group())
else:
print('不好意思,没有找到')
res = re.match('a', 'abcda') # 根据正则从头开始匹配(文本内容必须子啊开头匹配上)
print(res) # <_sre.SRE_Match object; span=(0, 1), match='a'>
print(res.group()) # a
""" 如果没有符合条件的数据,那么match返回None,而且使用group会直接报错"""
使用group不报错解决方案:
if res:
print(res.group())
else:
print('不好意思,没有找到')
re模块其他方法
import re
# 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
res = re.split('[ab]', 'abcd')
print(res)
# 类似于字符串类型的replace方法
res = re.sub('\d', 'H', 'eva3chick4yuan4', 1) # 替换正则匹配到的内容
print(res) # evaHchick4yuan4
res1 = re.sub('\d', 'H', 'eva3chick4yuan4') # 不写默认替换所有
print(res1) # evaHchickHyuanH
# 返回元组,并提示替换了几处
res = re.subn('\d', 'H', 'eva3chick4yuan4', 1)
print(res) # ('evaHchick4yuan4', 1)
res = re.subn('\d', 'H', 'eva3chick4yuan4')
print(res) # ('evaHchickHyuanH', 3)
# 常用
regexp_obj = re.compile('\d+')
res = regexp_obj.search('absd213j1hjj213jk')
res1 = regexp_obj.match('absd213j1hjj213')
res2 = regexp_obj.findall('1213k1j2jhj21j3123hh')
print(res, res1, res2)
# 常用
res = re.finditer('\d+', 'ashdklah21h23kj12jk3klj112312121kl131')
print([i.group() for i in res])
res = re.search("1(\d{14})(\d{2}[0-9x])?$", ‘110105199812067023’)
print(res) # <_sre.SRE_Match object; span=(0, 18), match=‘110105199812067023’>
print(res.group()) # 110105199812067023
print(res.group(1)) # 10105199812067
print(res.group(2)) # 023
# findall针对分组优先展示 无名分组
res = re.findall("^[1-9]\d{14}(\d{2}[0-9x])?$", '110105199812067023')
print(res) # ['023']
# 取消分组优先展示 无名分组
res1 = re.findall("^[1-9](?:\d{14})(?:\d{2}[0-9x])?$", '110105199812067023')
print(res1) # ['110105199812067023']
# 有名分组
res = re.search('^[1-9](?P<xx>\d{14})(?P<zz>\d{2}[0-9x])?$','110105199812067023')
print(res)
print(res.group())
print(res.group(1))
print(res.group('xx'))
print(res.group('zz'))
正则实战案例
import re
# 读取带匹配的数据
with open(r'a.txt', 'r', encoding='utf8') as f:
data = f.read()
# 利用正则匹配数据
# 分公司名称
title_list = re.findall('<h2>(.*?)</h2>', data)
# print(title_list)
# 分公司地址
address_list = re.findall("<p class='mapIco'>(.*?)</p>", data)
# print(address_list)
# 分公司邮箱
email_list = re.findall("<p class='mailIco'>(.*?)</p>", data)
# print(email_list)
# 分公司电话
phone_list = re.findall("<p class='telIco'>(.*?)</p>", data)
res = zip(title_list, address_list, email_list, phone_list)
for data_tuple in res:
print("""
公司名称:%s
公司地址:%s
公司邮箱:%s
公司电话:%s
""" % (data_tuple[0], data_tuple[1], data_tuple[2], data_tuple[3]))
collections模块
1.namedtuple(具名元组)
from collections import namedtuple
"""
namedtuple('名称',[名字1,名字2,...])
namedtuple('名称','名字1 名字2 ...')
"""
# point = namedtuple('坐标', ['x', 'y'])
# res = point(11, 22)
# print(res) # 坐标(x=11, y=22)
# print(res.x) # 11
# print(res.y) # 22
# point = namedtuple('坐标', 'x y z')
# res = point(11, 22, 33)
# print(res) # 坐标(x=11, y=22, z=33)
# print(res.x) # 11
# print(res.y) # 22
# print(res.z) # 33
# card = namedtuple('扑克', '花色 点数')
# card1 = card('♠', 'A')
# card2 = card('♥', 'K')
# print(card1)
# print(card1.花色)
# print(card1.点数)
2.队列
# 队列模块
import queue # 内置队列模块:FIFO
# 初始化队列
# q = queue.Queue()
# 往队列中添加元素
# q.put('first')
# q.put('second')
# q.put('third')
# 从队列中获取元素
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get()) # 值去没了就会原地等待
3.双端队列
from collections import deque
q = deque([11,22,33])
q.append(44) # 从右边添加
q.appendleft(55) # 从左边添加
print(q.pop()) # 从右边取值
print(q.popleft()) # 从做边取值
4.有序字典
normal_dict = dict([('name', 'jason'), ('pwd', 123), ('hobby', 'study')])
print(normal_dict)
{'hobby': 'study', 'pwd': 123, 'name': 'jason'}
from collections import OrderedDict
order_dict = OrderedDict([('name', 'jason'), ('pwd', 123), ('hobby', 'study')])
print(order_dict)
OrderedDict([('name', 'jason'), ('pwd', 123), ('hobby', 'study')])
order_dict['xxx'] = 111
order_dict
OrderedDict([('name', 'jason'), ('pwd', 123), ('hobby', 'study'), ('xxx', 111)])
normal_dict['yyy'] = 222
normal_dict
{'hobby': 'study', 'pwd': 123, 'yyy': 222, 'name': 'jason'}
5.默认值字典
from collections import defaultdict
values = [11, 22, 33,44,55,66,77,88,99,90]
my_dict = defaultdict(list)
for value in values:
if value>60:
my_dict['k1'].append(value)
else:
my_dict['k2'].append(value)
print(my_dict)
6.计数器
res = 'abcdeabcdabcaba'
# 统计字符串中每个元素出现的次数
# new_dict = {}
# for i in res:
# if i not in new_dict:
# new_dict[i] = 1
# else:
# new_dict[i] += 1
# print(new_dict)
from collections import Counter # 计数器
ret = Counter(res)
print(ret)
time模块
"""
时间三种表现形式
1.时间戳(秒数)
2.结构化时间(一般是给机器看的)
3.格式化时间(一般是给人看的)
三种时间是可以相互转换的!!!
"""
1.time.sleep() # 原地阻塞指定的秒数
2.time.time() # 获取时间戳时间(自1970-1-1 00:00)
import time
# 获取当前格式化的时间字符串
print(time.strftime('%Y-%m-%d')) # 2021-11-25
print(time.strftime('%Y-%m-%d %H:%M:%S')) # 2021-11-25 11:48:34
print(time.strftime('%Y-%m-%d %X')) # 2021-11-25 11:48:34
"""
更多时间相关符号 保存到容易查找的位置即可
"""
本地时区的struct_time(结构化的时间)
# print(time.localtime())
UTC时区的struct_time(结构化时间)
# time.struct_time(
# tm_year=2021,
# tm_mon=11,
# tm_mday=25,
# tm_hour=11,
# tm_min=51,
# tm_sec=25,
# tm_wday=3,
# tm_yday=329,
# tm_isdst=0)
# print(time.time())
print(time.gmtime(11111111111))
# print(time.localtime())
datetime模块
import datetime
# print(datetime.date.today()) # 2021-11-25
# print(datetime.datetime.today()) # 2021-11-25 12:15:11.969769
"""date年月日 datetime年月日时分秒 time时分秒(MySQL django后期可以)"""
# res = datetime.datetime.today()
# print(res.year) # 2021
# print(res.month) # 11
# print(res.day) # 25
# print(res.weekday()) # 获取星期(weekday星期是0-6) 0表示周一
# print(res.isoweekday()) # 获取星期(weekday星期是1-7) 1表示周一
"""时间差(timedelta)"""
# ctime = datetime.datetime.today()
# time_tel = datetime.timedelta(days=3)
# print(ctime) # 2021-11-25 12:20:48.570489
# print(ctime - time_tel) # 2021-11-22 12:21:06.712396
# print(ctime + time_tel) # 2021-11-28 12:21:06.712396
"""
日期对象 = 日期对象 +/- timedelta对象
timedelta对象 = 日期对象 +/- 日期对象
"""
# ret = ctime + time_tel
# print(ret - ctime) # 3 days, 0:00:00
# print(ctime - ret) # -3 days, 0:00:00
# 小练习 计算举例今年过生日还有多少天
# birthday = datetime.date(2000, 11, 11)
# now_date = datetime.date.today()
# days = birthday - now_date
# print('距离生日还有{}天'.format(days))
# UTC时间与我们的东八区时间差 八个小时
# print(datetime.datetime.now()) # 2021-11-25 12:25:33.579310
# print(datetime.datetime.utcnow()) # 2021-11-25 04:25:33.579310
random随机数模块
import random
print(random.random()) # 随机产生一个0-1之间的小数
print(random.randint(1, 6)) # 随机产生一个1-6之间的整数 比如:掷骰子
print(random.uniform(1, 6)) # 随机产生一个1-6之间的小数
print(random.choice(['特等奖', '一等奖', '二等奖', '谢谢惠顾'])) # 随机抽取一个
print(random.sample(['安徽省', '江苏省', '海南省', '山东省'], 2)) # 随机抽取指定样本量
l = [2, 3, 4, 5, 6, 7, 8, 9, 'J', 'Q', 'K', 'A']
random.shuffle(l) # 随机打乱容器类型中的诸多元素
print(l)
笔试题
# 随机验证码可以是由 数字 小写字母 大小写字母 任意组合
# 编写能够产生五位数的随机验证码
要求:五位,每位都可以是三种情况之一
def get_code(n):
# 提前定义一个存储验证码的变量
code = ''
# 由于需要产生五位,每一个操作都是一样的,所以肯定需要使用循环
for i in range(n):
# 随机产生一个数字
random_int = str(random.randint(0, 9))
# 随机产生一个大写字母
random_upper = chr(random.randint(65, 90))
# 随机产生一个小写字母
random_lower = chr(random.randint(97, 122))
# 随机选取一个
temp = random.choice([random_int, random_upper, random_lower])
# 拼接到字符串中
code += temp
return code
code1 = get_code(5)
code2 = get_code(10)
code3 = get_code(8)
print(code1, code2, code3)
os模块
是与操作系统打交道
import os
# 1. 创建单级目录(文件夹)
os.mkdir('dirname')
os.mkdir(r'dirname\作品') # 报错
# 2. 创建多级目录(文件夹)
os.makedirs(r'dirname1\dirname2')
# 3. 删除空目录(文件夹)
os.rmdir(r'dirname')
os.removedirs(r'dirname')
# 4. 获取当前文件所在的路径(可以嵌套 则为上一层路径)
BASE_DIR = os.path.dirname(__file__)
# 5. 路径拼接能够自动识别不同操作系统分隔符问题
movie_dir = os.path.join(BASE_DIR, '作品')
# 6. 列举出指定路径下的文件名称(任意类型文件)
data_list = os.listdir('D:\dirname\作品')
while True:
for i,j in enumerate(data_list):
print(i + 1, j)
choice = input('请选择想要的文件编号:').strip()
if choice.isdigit():
choice = int(choice)
if choice in range(len(data_list) + 1):
# 获取编号对应的文件名称
file_name = data_list[choice - 1]
# 拼接文件的完整路径 /专门用于路径拼接,而且能够自动识别当前操作系统的路径分隔符
file_name = os.path.join(movie_dir, file_name)
# 利用文件操作读写文件
with open(file_path, 'r', encoding='utf8') as f:
print(f.read())
# 7. 删除一个文件
os.remove('a.txt')
# 8. 修改文件名称
os.rename('老文件名', '新文件名')
# 9. 获取当前工作路径
print(os.getcwd())
# 10. 切换路径
os.chdir('D:/')
with open(r'a.txt', 'wb') as f:
pass
# 11. 判断当前路径是否存在,如果存在,返回True;如果不存在,返回False
print(os.path.exists('a.txt')) # False
print(os.path.exists('path')) # True
# 12. 判断当前路径是否是文件,如果path是一个存在的文件,返回True。否则返回False
os.path.isfile(path)
# 13. 判断当前路径是否是文件夹,如果path是一个存在的目录,则返回True。否则返回False
os.path.isdir(path)
# 14. 获取文件大小(字节数)
os.path.getsize(path)
sys模块
主要与python解释器打交道
sys.argv 命令行参数List,第一个元素是程序本身路径
sys.exit(n) 退出程序,正常退出时exit(0),错误退出sys.exit(1)
sys.version 获取Python解释程序的版本信息
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称
异常处理和status
try:
username = sys.argv[1]
password = sys.argv[2]
if username == 'chick' and password == '123':
print('正常执行文件内容')
else:
print('用户名或密码错误')
except Exception:
print('请输入用户名和密码')
序列化模块
json格式数据:跨语言传输
什么叫序列化——将原本的字典、列表等内容转换成一个字符串的过程叫序列化
序列化的目的
- 以某种存储形式使自定义对象持久化;
- 将对象从一个地方传递到另一个地方
- 使程序更具维护性
import json
d = {'username': 'jason', 'pwd': 123}
# 1.将python其他数据转换成json格式字符串(序列化)
# import json
# res = json.dumps(d)
# print(res,type(res)) # {"username": "jason", "pwd": 123}
# 2.将json格式字符串转成当前语言对应的某个数据类型(反序列化)
# res1 = json.loads(res)
# print(res1,type(res1)) # {'username': 'jason', 'pwd': 123} <class 'dict'>
# bytes_data = b'{"username": "jason", "pwd": 123}'
# bytes_str = bytes_data.decode('utf8')
# bytes_dict = json.loads(bytes_str)
# print(bytes_dict,type(bytes_dict))
"""
暂且可以简单的理解为
序列化就是将其他数据类型转换成字符串过程
json.dumps()
反序列化就是将字符串转换成其他数据类型
json.loads()
"""
# 将字典d写入文件
# with open(r'a.txt','w',encoding='utf8') as f:
# f.write(str(d))
# 将字典d取出来
# with open(r'a.txt','r',encoding='utf8') as f:
# data = f.read()
# print(dict(data))
# 将字典d写入文件
# with open(r'a.txt','w',encoding='utf8') as f:
# res = json.dumps(d) # 序列化成json格式字符串
# f.write(res)
# 将字典d取出来
# with open(r'a.txt','r',encoding='utf8') as f:
# data = f.read()
# res1 = json.loads(data)
# print(res1,type(res1))
# d1 = {'username': 'tony', 'pwd': 123,'hobby':[11,22,33]}
# with open(r'a.txt', 'w', encoding='utf8') as f:
# json.dump(d1, f)
# with open(r'a.txt','r',encoding='utf8') as f:
# res = json.load(f)
# print(res,type(res))
d1 = {'username': 'tony好帅哦 我好喜欢', 'pwd': 123,'hobby':[11,22,33]}
print(json.dumps(d1,ensure_ascii=False))
"""
# 并不是所有的数据类型都支持序列化
json.JSONEncoder 查看支持的数据类型
"""
subprocess模块
import subprocess
"""
1.可以基于网络连接上一台计算机(socket模块)
2.让连接上的计算机执行我们需要执行的命令
3.将命令的结果返回
"""
res = subprocess.Popen('tasklist',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
print('stdout',res.stdout.read().decode('gbk')) # 获取正确命令执行之后的结果
print('stderr',res.stderr.read().decode('gbk')) # 获取错误命令执行之后的结果
"""
windows电脑内部编码默认为GBK
"""
hashlib模块
加密:将明文数据通过一系列算法变成密文数据(目的就是为了数据的安全)
加密算法:md系列 sha系列 base系列 hmac系列
# 基本使用
import hashlib
# 1.先确定算法类型(md5普遍使用)
md5 = hashlib.md5()
# 2.将明文数据传递给md5算法(update只能接受bytes类型数据)
# md5.update('123'.encode('utf8'))
md5.update(b'123')
# 3.获取加密之后的密文数据(没有规则的一串随机字符串)
res = md5.hexdigest()
print(res)
1.加密之后的密文数据是没有办法反解密成明文数据的
市面上的破解 其实就是提前算出一系列明文对应的密文之后对比密文再获取明文
明文数据很大,可以分块多次调用update(),最后计算的结果是一样的:
import hashlib
# 1.先确定算法类型(md5普遍使用)
md5 = hashlib.md5()
# 2.将明文数据传递给md5算法(update只能接受bytes类型数据)
# md5.update('123'.encode('utf8'))
# md5.update(b'hellojason123')
md5.update(b'hello')
md5.update(b'jason')
md5.update(b'123') # 4bd388611b31c548eedef14b16c9868c
# 3.获取加密之后的密文数据(没有规则的一串随机字符串)
res = md5.hexdigest()
print(res) # 4bd388611b31c548eedef14b16c9868c
密文数据越长表示内部对应的算法越复杂 越难被正向破解
import hashlib
# 1.先确定算法类型(md5普遍使用)
md5 = hashlib.sha256()
# 2.将明文数据传递给md5算法(update只能接受bytes类型数据)
# md5.update('123'.encode('utf8'))
# md5.update(b'hellojason123')
md5.update(b'hello')
md5.update(b'jason')
md5.update(b'123') # 6ec0f865ec4e9bcf9abc7f6c0e7268acfb2ba36f3e460fd592a214f7eacc92b0
# 3.获取加密之后的密文数据(没有规则的一串随机字符串)
res = md5.hexdigest()
print(res) # 6ec0f865ec4e9bcf9abc7f6c0e7268acfb2ba36f3e460fd592a214f7eacc92b0
密文越长表示算法越复杂,对应的破解算法的难度越高
但是越复杂的算法所需要消耗的资源也就越多,密文越长基于网络发送需要占据的数据也就越大
具体使用什么算法取决于项目的要求,一般情况下md5足够了
涉及到用户密码存储,其实就是密文,只要用户自己知道明文是什么
- 内部程序员无法得知明文数据
- 数据泄露也无法得知明文数据
加盐处理
“”"
在对明文数据做加密处理过程前添加一些干扰项
“”"
import hashlib
# 1.先确定算法类型(md5普遍使用)
md5 = hashlib.md5()
# 2.将明文数据传递给md5算法(update只能接受bytes类型数据)
# md5.update('123'.encode('utf8'))
# 加盐(干扰项)
md5.update('公司内部自己定义的盐'.encode('utf8'))
# 真实数据
md5.update(b'hellojason123')
# 3.获取加密之后的密文数据(没有规则的一串随机字符串)
res = md5.hexdigest()
print(res) # 4326fe1839d7c4186900eb2b356d4f8a
动态加盐
“”"
在对明文数据做加密处理过程前添加一些变化的干扰项
“”"
import hashlib
# 1.先确定算法类型(md5普遍使用)
md5 = hashlib.md5()
# 2.将明文数据传递给md5算法(update只能接受bytes类型数据)
# md5.update('123'.encode('utf8'))
# 加盐(干扰项)
# md5.update('公司内部自己定义的盐'.encode('utf8'))
# 动态加盐(干扰项) 当前时间 用户名的部分 uuid(随机字符串(永远不会重复))
import time
res1 = str(time.time())
md5.update(res1.encode('utf8'))
# 真实数据
md5.update(b'hellojason123')
# 3.获取加密之后的密文数据(没有规则的一串随机字符串)
res = md5.hexdigest()
print(res) # 51033f8091108d2e399843e23b0b6a25
“”"
在IT互联网领域,没有绝对的安全可言,只有更安全
原因在于互联网的本质,就是通过网络(网卡)连接计算机
“”"
校验文件一致性
“”"
文件不是很大的情况下 可以将所有文件内部全部加密处理
但是如果文件特别大 全部加密处理相当的耗时好资源 如何解决???
针对大文件可以使用切片读取的方式
“”"
import hashlib
md5 = hashlib.md5()
with open(r'a.txt','rb') as f:
for line in f:
md5.update(line)
real_data = md5.hexdigest()
print(real_data) # 29d8ea41c610ee5d1e76dd0a42c7e60a
with open(r'a.txt','rb') as f:
for line in f:
md5.update(line)
error_data = md5.hexdigest()
print(error_data) # 738a56b49f24884ba758d1e4ab6ceb74
import os
# 读取文件总大小
res = os.path.getsize(r'a.txt')
# 指定分片读取策略(读几段 每段几个字节) 10 f.seek()
read_method = [0,res//4,res//2,res]
logging日志模块
import logging
# 日志有五个等级(从上往下重要程度不一样)
logging.debug('调试debug') # 10
logging.info('消息info') # 20
logging.warning('警告warn') # 30
logging.error('错误error') # 40
logging.critical('严重critical') # 50
'''默认记录的级别在30及以上'''
# 简单使用
import logging
file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',)
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
handlers=[file_handler,],
level=logging.ERROR
)
logging.error('日志模块很好学 不要自己吓自己')
"""
1.如何控制日志输入的位置
想在文件和终端中同时打印
2.不同位置如何做到不同的日志格式
文件详细一些 终端简单一些
"""
日志模块详细介绍
import logging
# 1.logger对象:负责产生日志
logger = logging.getLogger('转账记录')
# 2.filter对象:负责过滤日志(直接忽略)
# 3.handler对象:负责日志产生的位置
hd1 = logging.FileHandler('a1.log',encoding='utf8') # 产生到文件的
hd2 = logging.FileHandler('a2.log',encoding='utf8') # 产生到文件的
hd3 = logging.StreamHandler() # 产生在终端的
# 4.formatter对象:负责日志的格式
fm1 = logging.Formatter(
fmt='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
)
fm2 = logging.Formatter(
fmt='%(asctime)s - %(name)s %(message)s',
datefmt='%Y-%m-%d',
)
# 5.绑定handler对象
logger.addHandler(hd1)
logger.addHandler(hd2)
logger.addHandler(hd3)
# 6.绑定formatter对象
hd1.setFormatter(fm1)
hd2.setFormatter(fm2)
hd3.setFormatter(fm1)
# 7.设置日志等级
logger.setLevel(30)
# 8.记录日志
logger.debug('写了半天 好累啊')
配置字典
import 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'
logfile_path = 'a3.log'
# 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)传递
}, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
},
}
# 使用配置字典
logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中的配置
logger1 = logging.getLogger('xxx')
logger1.debug('好好的 不要浮躁 努力就有收获')
第三方模块
# 并不是python自带的 需要基于网络下载!!!
'''pip所在的路径添加环境变量'''
下载第三方模块的方式
方式1:命令行借助于pip工具
pip3 install 模块名 # 不知道版本默认是最新版
pip3 install 模块名==版本号 # 指定版本下载
pip3 install 模块名 -i 仓库地址 # 临时切换
'''命令行形式永久修改需要修改python解释器源文件'''
方式2:pycharm快捷方式
settings
project
project interprter
双击或者加号
点击右下方manage管理添加源地址即可
# 下载完第三方模块之后 还是使用import或from import句式导入使用
"""
pip命令默认下载的渠道是国外的python官网(有时候会非常的慢)
我们可以切换下载的源(仓库)
(1)阿里云 http://mirrors.aliyun.com/pypi/simple/
(2)豆瓣 http://pypi.douban.com/simple/
(3)清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/
(4)中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/
(5)华中科技大学http://pypi.hustunique.com/
pip3 install openpyxl -i http://mirrors.aliyun.com/pypi/simple/
"""
"""
下载第三方模块可能报错的情况及解决措施
1.报错的提示信息中含有关键字timeout
原因:网络不稳定
措施:再次尝试 或者切换更加稳定的网络
2.找不到pip命令
环境变量问题
3.没有任何的关键字 不同的模块报不同的错
原因:模块需要特定的计算机环境
措施:拷贝报错信息 打开浏览器 百度搜索即可
pip下载某个模块报错错误信息
"""
包介绍
-
什么是包?
# 官网解释 包是一种通过使用‘ .模块名’来组织python模块名称空间的方式 # 具体的:包就是一个包含有__init__.py文件的文件夹,所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来 # 需要强调的是: 1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,报下一定要有该文件,否则import 包报错 2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块
-
为何要使用包
包的本质就是一个文件夹,那么文件夹唯一的功能就是将文件组织起来 随着功能越写越多,我们无法将所有功能都放到一个文件中,于是我们使用模块去组织功能,而随着模块越来越多, 我们就需要用文件夹将模块文件组织起来,以此来提高程序的结构性和可维护性
-
注意事项
#1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。 #2、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件 #3、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间
1-9 ↩︎