【周报】模块2
上周回顾
常见内置函数
函数名 | 作用 | 参数 |
---|---|---|
abs | 求绝对值 | (int | float) |
all | 判断容器类型中的数据是否都为True | (容器类型) |
any | 判断容器类型中的数据是否存在True | (容器类型) |
bin | 十进制转二进制 | 十进制数 |
oct | 十进制转八进制 | 十进制数 |
hex | 十进制转十六进制 | 十进制数 |
int | 其他进制转十进制 | 其他进制数 |
bytes | 对字符串类型数据进行编码 | (str, 编码方式) |
callable | 判断变量名是否可调用 | (名字) |
chr | 基于ASCII码 将数字转字符 | (int) |
ord | 基于ASCII码 将字符转数字 | (单个str) |
dir | 获取对象中可以用句点符取出的数据和方式 | (名字) |
divmod | 获取除法运算后的整数与余数 常用作分页 | (int, int) |
enumerate | 枚举容器类型中的数据值 | (容器类型, start=int) |
eval | 识别字符串中的较简易的python代码 | (str) |
exec | 识别字符串中的较复杂的python代码 | (str) |
hash | 返回一串随机的数字(哈希值) | \ |
help | 查看帮助信息 | \ |
isinstance | 判断某个数据是否属于某个数据类型 | (数据, 数据类型) |
pow | 幂指函数 | (int, int) |
round | 四舍五入 有偏差 | (int | float) |
迭代
如何理解迭代
迭代,既更新换代,每次迭代都基于上一次的结果
可迭代对象
如何判断可迭代对象
可迭代对象可以使用句点符调用__iter__方法,并转化为迭代器对象
l1 = [1, 2, 3, 4, 5, 6, 7]
print(l1) # [1, 2, 3, 4, 5, 6, 7]
print(l1.__iter__()) # <list_iterator object at 0x0000020E538F9040>
已知的可迭代对象有:
字符串 列表 字典 元组 集合 文件
不可迭代对象有:
整型 浮点型 布尔值 函数名
迭代器对象
迭代器对象的作用
迭代器对象给我们提供了一种不依赖于索引值的取值方式
正是有迭代器对象的存在 我们才可以从字典、集合这些无序排序的容器类型中获取数据
如何判断迭代器对象
迭代器对象可以通过句点符调用__iter__和__next__方法,迭代器对象无论调用多少次__iter__都还是他本身
l1 = [1, 2, 3, 4, 5]
iter_obj = l1.__iter__()
print(iter_obj) # <list_iterator object at 0x000001CB9F4D90D0>
print(iter_obj.__next__()) # 1
print(iter_obj.__next__()) # 2
print(iter_obj.__next__()) # 3
print(iter_obj.__iter__()) # <list_iterator object at 0x000001CB9F4D90D0>
可迭代对象和迭代器对象的关系
可迭代对象调用__iter__会产生一个迭代器对象
迭代器对象无论使用多少次__iter__都还是他本身
迭代器对象取值
l1 = [1, 2, 3, 4, 5]
# l1 并没有 __next__ 方法 因为它是可迭代对象
res = l1.__iter__() # 可迭代对象使用__iter__将产生一个迭代器对象 并赋值给res
print(res.__next__()) # 1 使用__next__就可以取出下一个数据
# 不使用for循环 依次打印列表中所有数据
l1 = [1, 2, 3, 4, 5]
res = l1.__iter__()
n = 0
while n < len(l1):
print(res.__next__())
n += 1
# 运行结果
# 1
# 2
# 3
# 4
# 5
迭代取值与索引取值的区别
迭代取值能够对无序的数据集进行取值,但只能一个个获取数据,并且不能重复获取
索引取值能够随意重复获取任意位置的数据,但无法对无序的数据集进行取值
双下方法的另一种形式
res = l.__iter__() # 可以简写 res = iter(l)
res.__next__() # 可以简写 next(res)
# 不推荐
迭代器对象的特殊性
迭代器对象 通过打印操作无法直接看出内部的情况
这个时候能帮你节省空间
相当于一个工厂 需要数据时 一个个取出
异常捕获
如何理解异常
异常在程序运行中出现则会是程序直接结束
既程序员口中的BUG
异常的结构
关键字line
精准标记出异常的出现位置 一般来说看最后的超链接
最后一行冒号的左边
异常类型
最后一行冒号的右边
异常的具体原因(关键)
异常的分类
语法错误
不允许出现!出现就立马修改!
逻辑错误
允许出现 运行之后修改错误即可
什么时候需要异常
有不确定因素报错的情况下
异常捕获原理
预知了错误的可能 并提前给出相应的处理措施
异常语法结构
# 基本语法结构
try:
可能出错的代码 # 被try监控
except 错误类型1 as e: # e就是错误信息
针对错误类型1的解决方案
except 错误类型2 as e: # e就是错误信息
针对错误类型2的解决方案
except 错误类型3 as e: # e就是错误信息
针对错误类型3的解决方案
# 万能结构 不推荐
# 1
try:
可能出现错误的代码
except BaseException:
解决方案
# 2
try:
可能出现错误的代码
except Exception:
解决方案
异常捕获其他操作补充
# else和finally
try:
可能出现错误的代码
except 错误类型:
针对错误类型的解决方法
else:
不报错后执行的代码
finally:
报不报错都会执行的代码
# assert 断言
name = 'jason'
assert isinstance(name, list) # 断言name 属于 list类型 如果不对则报错 对则执行后面的代码 感觉和if作用差不多
print('哈哈哈哈哈') # 显然name不是list类型 所以这步不会执行
# raise 主动抛出异常
name = 'jason'
if name == 'jason':
raise Exception('鸡你太美')
else:
raise Exception('你干嘛~')
生成器
生成器对象的本质
本质就是迭代器对象
但迭代器对象是编译器提供给我们的
而生成器对象是我们根据迭代器对象 依赖yield关键字 生成的
生成器对象的作用
优化代码 提供一种不依赖与索引的取值方式 并在需要数据时一个一个取出 节省了占用空间
代码实现
# yield关键字
def func():
print(123)
yield
func() # 运行后发现 啥也没有
# 原来 当函数体内有yield关键字 第一次运行时并不会执行函数体代码 而是产生一个迭代器对象 既生成器 可以由一个变量名接收
res = func()
res.__next__() # 123 通过调用__next__方法就可以调用yield上面的代码
# 当然 函数体内可以不止有一个yield
def func():
print(1)
yield
print(2)
yield
print(3)
yield
print(4)
yield
res = func()
res.__next__() # 1
res.__next__() # 2
res.__next__() # 3
res.__next__() # 4
# yield 后面可以添加返回值 和return用法相似
def func():
print(1)
yield 111
print(2)
yield 222
print(3)
yield 333
res = func()
res1 = res.__next__() # 1
res2 = res.__next__() # 2
res3 = res.__next__() # 3
print(res1) # 111
print(res2) # 222
print(res3) # 333
yield关键字其他用法
# yield可以在函数中充当一个参数
def func(name, s_name=None):
print(f'{name}要来检查博客辣!!!')
while True:
s_name = yield
print(f'哦吼!{s_name}博客没写 录音也没录')
res = func('jason') # 同样第一次调用不会执行函数体代码
res.__next__() # jason要来检查博客辣!!! 必须先调用一次__next__()
res.send('快男') # 哦吼!快男博客没写 录音也没录 send()用于传值给yield 并自动调用__next__方法
res.send('XXX') # 哦吼!XXX博客没写 录音也没录
生成器表达式
n = 1
l1 = (i + n for i in range(10))
print(l1) # <generator object <genexpr> at 0x000001A04F4DCAC0> "元组生成式"生成了一个生成器对象
# 只有在执行__next__时 i+1才会执行 并将结果返回
print(list(l1)) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
l2 = (i + n for i in range(10))
n = 2 # 修改了n = 2
print(list(l2)) # [2, 3, 4, 5, 6, 7, 8, 9, 10, 11] 执行了修改后的n
# 面试题
def add(n, i): # 普通函数 返回两个数的和 求和函数
return n + i
def test(): # 生成器
for i in range(4):
yield i
g = test() # 激活生成器
for n in [1, 10]:
g = (add(n, i) for i in g)
"""
第一次for循环
g = (add(1, i) for i in g) # 这里并没有调用 只是产生了一个迭代器(生成器)
第二次for循环
g = (add(10, i) for i in (add(10, i) for i in g)) # 这里的add()中的n变为了10 然后再产生了一个生成器
"""
res = list(g) # 这里才进行了调用 n为10 所以全部生成器中n都为10
"""
大致过程
先:g = (add(10, i) for i in (10, 11, 12, 13))
再 res = (20, 21, 22, 23)
"""
print(res)
#A. res=[10,11,12,13]
#B. res=[11,12,13,14]
#C. res=[20,21,22,23] # 正确答案
#D. res=[21,22,23,24]
模块
如何理解模块
模块就像一个工具箱 里面装有各种工具
导入了模块就能使用其中的名字和功能
模块的分类
内置模块
自定义模块
第三方模块
模块表现形式
py文件
含有多个py文件的文件夹
模块的两种导入方式
# 方式1:import ...
import time
time.sleep()
# 方式2: from ... import ...
from time import sleep
sleep()
# import ...
# 优点 通过模块.的方式可以使用到模块内的全部名字 且不会冲突
# 缺点 暴露太多 有时候并不想所有东西都可以通过模块.的方式获取
# from ... import ...
# 优点 指名道姓的使用指定的名字 并且不需要加模块名前缀
# 缺点 名字容易于当前全局名称空间的名字产生冲突
模块补充说明
# 起别名
# 在多个模块名字相同 或 模块名较复杂的情况下 可以通过 as 别名 的方式取一个别名
# 再通过别名.的形式调用模块内的功能
import UserInfoGetTargetName as UIGT
UIGT.XXXXX
from a import d as a_d
from b import d as b_d
from c import d as c_d
# 同时导入多个名字
# 建议同一目录下的模块 或 功能相似的模块 采用统一导入
from a import b, c, d
import run, runfast, runslowly
判断文件类型
所有py文件都含有一个内置的名字__name__
当py文件为执行文件时__name__为__main__
当py文件为被导入文件时__name__为文件名(模块名)
循环导入问题
# 以下为a.py的内容
import b
name = 'from a'
print(b.name)
# 以下为b.py的内容
import a
name = 'from b'
print(a.name)
# 无论执行哪个文件都会报错
# 解决措施
# 在导入前先把东西准备好
# 以下为a.py的内容
name = 'from a'
import b
print(b.name)
# 以下为b.py的内容
name = 'from b'
import a
print(a.name)
模块查找顺序
先在内存中查找>>>再去内置中查找>>>在去环境变量中查找(sys.path)
所有的路径都是参照执行文件来的
可以通过 sys.path.append() 的方式添加文件的绝对路径
可以通过 from ... import ... 获取相对路径下的模块 起始位置一定是执行文件所在的位置
绝对导入与相对导入
前提
只要提到模块的导入 那么sys.path永远以执行文件为基准
绝对导入
from ccc.ddd.eee impot a
绝对导入会按照当前执行文件的sys.path一层层的往下查找
pycharm默认将项目根目录存放在sys.path中 所以从项目根目录一层层导入绝对不会出错
但若不是用pycharm运行 则需要将项目根目录路径添加到sys.path
所以还是养成手动将根目录添加到sys.path中的习惯
提高项目兼容性
相对导入
模块文件之间的导入会使用到相对导入
但绝对导入更好
.在路径中的作用
标点 | 作用 |
---|---|
. | 当前文件路径 |
.. | 上一级文件路径 |
../.. | 上上级文件路径 |
相对导入可以不参考执行文件所在的路径 直接以当前模块路径为准
但相对导入有些缺陷:
1.只能在模块文件中使用 不在执行文件中使用
2.相对导入在项目比较复杂的情况下 可能会出错
建议:多用绝对导入 少用相对导入
包的概念
如何理解包
专业角度:内部含有__init__.py的文件夹
直观角度:内部有模块文件的文件夹
作用:存放多个模块 仅仅是更加方便的管理模块文件
包的使用
import 包名
可以看到这里导入的是包内的__init__.py文件
但也可以通过from ... import ...的方式跳过__init__.py文件直接获取包内的模块文件
不同版本导入包的差异
python3解释器中包内有没有__init__.py都无所谓了
而python2解释器中包内严格需求要有__init__.py
python2环境下
编程思想
小白阶段
按需求从上往下的编写代码(面条版)-----单文件
函数阶段
打破从上往下编写代码的空间限制 按功能将代码封装为不同函数-----单文件
模块阶段
把封装好的函数按功能分类并拆分到不同的模块中-----多文件
每个阶段都使代码变得更加规范
软件开发目录规范
目的
为了更加方便、高效、快捷的管理代码
文件夹 | 作用 | 内含文件 |
---|---|---|
conf | 存储程序的配置文件 | settins.py |
core | 存储程序的核心功能 | src.py |
bin | 存储程序的启动文件 | start.py |
lib | 存储程序的公共功能 | common.py |
db | 存储程序的数据文件 | userinfo.txt |
log | 存储程序的日志文件 | log.log |
interface | 存储程序的接口文件 | user.py、good.py |
readme(单个文件) | 用于介绍程序的功能 | \ |
requirements.txt(单个文件) | 记录了项目所需的第三方模块名称和版本信息 | \ |
collections模块
作用
给我们提供了更多的数据类型
名字 | 类型 |
---|---|
namedtuple | 具名元组 |
deque | 双端队列 |
OrderedDict | 有序字典 |
defaultdict | 默认值字典 |
counter | 计数器 |
time模块
作用
提供了很多时间的操作
函数 | 作用 |
---|---|
time() | 获取时间戳 |
localtime() | 获取结构化时间 |
gmtime() | 获取英国伦敦的结构化时间 |
strftime() | 根据某舟格式来格式化时间 |
sleep() | 程序在原地等待自定义的时间 |
时间的格式
在striftime()中输入特定的格式可以获取特定的时间字符串
import time
res = time.strftime('%Y-%m-%d %H:%M:%S')
print(res) # 2022-07-15 17:11:02
res = time.strftime('%Y-%m-%d %X')
print(res) # 2022-07-15 17:11:02
格式 | 作用 |
---|---|
%Y | 获取年份 |
%m | 获取月份 |
%d | 获取天份 |
%H | 获取小时 |
%M | 获取分钟 |
%S | 获取秒数 |
%X | 获取时分秒 |
datetime模块
与time模块类似 都是时间相关操作的模块
使用
import datetime
res = datetime.datetime.today()
print(res) # 2022-07-15 17:18:49.814341
res1 = datetime.date.today()
print(res1) # 2022-07-15
"""
date 年月日
datetime 年月日 时分秒
"""
print(res.year) # 2022
print(res.month) # 7
print(res.day) # 15
print(res.hour) # 17
print(res.minute) # 22
print(res.second) # 16
print(res.weekday()) # 4
print(res.isoweekday()) # 5
"""
year 年
moth 月
day 日
hour 时
minute 分
second 秒
weekday() 周几 周一为0
isoweekday()周几 周一为1
"""
# timedelta 日期延期/提前
res = datetime.date.today()
tl = datetime.timedelta(days=3)
print(res) # 2022-07-15
print(res + tl) # 2022-07-18
print(res - tl) # 2022-07-12
"""
timedelta括号内有很多参数 没有的时间可以通过换算得来
"""
os模块
语句
# 导入
import os
import os
# 创建目录 mkdir() makedirs()
os.mkdir(r'aaa') # 创建单级文件 但不能创建多级文件 但mkdir该语句在很多系统都通用
os.makedirs(r'aaa\bbb\ccc') # 创建多级文件 也可以创建单级文件
import os
# 删除目录 rmdir() removedirs()
os.rmdir(r'aaa') # 删除单级文件 但文件内不能有数据 不能删除多级文件
os.removedirs(r'aaa\bbb\ccc') # 可以删除多级文件
# 但若文件内有数据则无法删除 从内到外依次删除空的文件夹 直到遇到有数据的文件夹
import os
# 列举指定文件下的文件名称 listdir() 结果返回的是列表
# aaa文件夹中有 a.py b.py c.py
res = os.listdir(r'aaa')
print(res) # ['a.py', 'b.py', 'c.py']
import os
# 重命名文件 rename() 删除文件 remove()
os.rename('a.txt', r'aaa.txt') # 将a.txt更改为aaa.txt
os.remove('aaa.txt') # 删除aaa.txt
import os
# 获取当前工作路径 getcwd() 获取的是绝对路径
print(os.getcwd()) # F:\pythonProject\day24
os.chdir(r'..') # chdir() 类似 控制台中的cd
print(os.getcwd()) # F:\pythonProject
import os
# 与程序启动文件相关
print(os.path.abspath(__file__)) # 获取当前文件的绝对路径(可以不记)
print(os.path.dirname(__file__)) # 获取当前文件所在的目录路径(必须得记)
import os
# 判断路径是否存在(文件、目录) exists() isdir() isfile()
# exists() 就像 isdir() 和 isfile() 功能的结合版
# isdir() 只能判断路径是否是目录(既文件夹)
# isfile() 只能判断路径是否是文件
# exists() 可以判断路径是否存在
import os
# 拼接路径 join()
relative_path = 'a.txt'
absolute_path = r'D:\pythonProject\day24\ccc\ddd\eee'
res = os.path.join(absolute_path, relative_path) # 两个路径之间会根据当前系统自动添加\或/(不同系统之间路径的分隔符不同)
print(res) # D:\pythonProject\day24\ccc\ddd\eee\a.txt
import os
# 获取文件大小 getize()
# a.txt 的内容如下
# 你好aaaa
print(os.path.getsize(r'a.txt')) # 10 计算的是字节量 1个中文3字节 1个英文1个字节 所以是10字节
sys模块
语句
import sys
print(sys.path) # 结果是列表
print(sys.version) # 查看解释器版本信息
print(sys.platform) # 查看当前平台
res = sys.argv
"""需求 命令行执行当前文件必须提供用户名和密码 否则不准执行"""
if len(res) == 3:
username = res[1]
password = res[2]
if username == 'jason' and password == '123':
print('您可以正常执行该文件')
else:
print('用户名或密码错误')
else:
print('请填写用户名和密码')
# 上述校验也可以使用异常捕获实现(课下实现)
res = sys.argv
try:
username = res[1]
password = res[2]
if username == 'jason' and password == '123':
print('您可以正常执行该文件')
else:
print('用户名或密码错误')
except IndexError:
print('请输入用户名和密码')
json模块
语句
import json
res = json.dumps(d) # 序列化 将其他数据类型转换成json格式字符串
print(res, type(res)) # {"name": "jason", "pwd": 123} <class 'str'>
res1 = json.loads(res) # 反序列化 将json格式字符串转换成对应编程语言中的数据类型
print(res1, type(res1)) # {'name': 'jason', 'pwd': 123} <class 'dict'>
"""
dumps() 将其他数据类型转换为json格式字符串
loads() 将json格式字符串z换行成对应的数据类型
dump() 将其他数据类型直接以json格式字符串写入文件
load() 将文件中json格式字符串读取出来并转换成对应的数据类型
"""
本周回顾
正则表达式
前言:该知识点不属于任何一门编程语言 是一个独立的知识点
用纯python代码实现手机号验证
# 纯python
# 1.输入手机号
phone = input('请输入手机号>>>:').strip()
# 2.判断是否是纯数字
if phone.isdigit():
# 3.判断是否以13 15 17 18 19开头
if phone.startswith('13') or phone.startswith('15') or phone.startswith('17') or phone.startswith('18') or phone.startswith('19'):
# 4.判断是否长度为11位
if len(phone) == 11:
print('合法辣')
else:
print('手机长度不对')
else:
print('开头不对')
else:
print('请输入正确手机号')
使用正则实现手机号验证
# 正则
import re
# 1.输入手机号
phone = input('请输入手机号>>>:').strip()
# 2.使用match方法
if re.match('^(13|15|17|18|19)[0-9]{9}', phone):
print('合法')
else:
print('不合法')
正则表达式本质上就是使用一些符号的组合产生一些特殊的含义
然后去字符串中筛选出符合条件的数据
正则表达式之字符组
字符组在没有量词修饰下一次只会针对一个数据值
字符组 | 作用 |
---|---|
[0-9] | 每次匹配一个数字 |
[a-z] | 每次匹配一个小写字母 |
[A-Z] | 每次匹配一个大写字母 |
[0-9a-zA-Z] | 每次匹配一个数字或大写字母或小写字母 |
中括号内编写的多个数据彼此之间为或关系
正则表达式之特殊符号
特殊符号在没有量词修饰的情况一个符号一次只会针对一个数据值
特殊符号 | 作用 |
---|---|
. | 匹配除换行符以外的所有字符 |
\w | 匹配下划线、字母、数字 |
\W | 匹配非(下划线、字母、数字) |
\d | 匹配数字 |
^ | 匹配开头 |
$ | 匹配结尾 |
a|b | 匹配a或匹配b |
() | 给正则表达式分组 不影响正则表达式的匹配 |
[] | 匹配字符组中的字符 |
[^] | 匹配非字符组中字符的字符 |
正则表达式之量词
在正则表达式中所有的量词默认都是贪婪匹配(尽可能多的)
量词不能单独使用 必须跟在表达式的后面 并且只能影响紧挨着的左边那一个
量词 | 作用 |
---|---|
* | 匹配0个或多个 |
+ | 匹配1个或多个 |
? | 匹配0个或1个 |
匹配n个 | |
匹配n到m个 |
贪婪匹配与非贪婪匹配
# 贪婪匹配
s = '<div>这是个测试文本</div>'
res = re.findall('<.*>', s)
print(res) # ['<div>这是个测试文本</div>']
# 非贪婪匹配
s = '<div>这是个测试文本</div>'
res = re.findall('<.*>', s)
print(res) # ['<div>', '</div>']
"""
所有的量词默认都是贪婪匹配 但是如果在量词的后面紧跟一个问号
那么就会变成非贪婪匹配
小技巧:以后我们在使用贪婪匹配或者非贪婪匹配的时候一般都是用.*或者.*?
并且结束的标志有上述符号左右两边添加的表达式决定
"""
取消转义
正则表达式中 \n
python中 r'\n'
re模块
re模块是python中处理正则的一种模块 并不是唯一
findall()
import re
# findall() 通过正则表达式筛选出文本中所有符合的数据 返回值为列表
res = re.findall('abc', 'abcabcabcabc')
print(res) # ['abc', 'abc', 'abc', 'abc']
finditer()
# finditer() 通过正则表达式筛选出文本中所有符合的数据 返回值为迭代器对象
res = re.finditer('abc', 'abcabcabcabc')
print(res) # <callable_iterator object at 0x000001BF27557220>
print(res.__next__()) # <re.Match object; span=(0, 3), match='abc'>
print(res.__next__().group()) # abc
search()
# search() 通过正则表达式筛选文本中第一个符合条件的数据
res = re.search('abc', 'abcabcabcabc')
print(res) # <re.Match object; span=(0, 3), match='abc'>
print(res.group()) # abc
match()
# match() 从头开始匹配正则表达式 若头部都不符合 则直接退出 类似^
res = re.match('abc', 'abcabcabcabc')
print(res) # <re.Match object; span=(0, 3), match='abc'>
print(res.group()) # abc
res = re.match('abc', 'bcabcabcabc')
print(res) # None
compile()
# compile() 提前准备好正则 方便使用 减少代码冗余
obj = re.compile('abc')
print(re.findall(obj, 'abcabc')) # ['abc', 'abc']
print(re.findall(obj, 'abcabcabc')) # ['abc', 'abc', 'abc']
print(re.findall(obj, 'abcabcccabcabc')) # ['abc', 'abc', 'abc', 'abc']
findall() 补充
# findall针对分组的正则表达式匹配到的结果 优先展示
res = re.findall('a(b)c', 'abcabcabcabc')
print(res) # ['b', 'b', 'b', 'b']
res = re.findall('a(bc)', 'abcabcabcabc')
print(res) # ['bc', 'bc', 'bc', 'bc']
# 可以使用:?取消优先展示
res = re.findall('a(?:b)c', 'abcabcabcabc')
print(res) # ['abc', 'abc', 'abc', 'abc']
res = re.findall('a(?:bc)', 'abcabcabcabc')
print(res) # ['abc', 'abc', 'abc', 'abc']
还能起别名(?P<name>正则表达式)
import re
res = re.finditer('a(?P<cccc>b)c', 'abcabcabc')
print(res.__next__().group('cccc')) # b
网络爬虫
什么是互联网
将计算机连接在一起的网络
互联网发明的目的
数据分享
上网的本质
访问他人计算机内的资源(一般有专门用来供他人访问的计算机 这种计算机称之为服务器)
网络爬虫的本质
模拟计算机浏览器想目标网站发送请求获取数据并筛选
只要是浏览器可以访问的数据 网络爬虫一般来说都可以
第三方模块的下载
方式1:pip install 模块名==版本号
方式2:pycharm内在settings里下载
下载速度慢
pip 工具默认使用国外的源
可以手动添加源
清华大学 :https://pypi.tuna.tsinghua.edu.cn/simple/
阿里云:http://mirrors.aliyun.com/pypi/simple/
中国科学技术大学 :http://pypi.mirrors.ustc.edu.cn/simple/
华中科技大学:http://pypi.hustunique.com/
豆瓣源:http://pypi.douban.com/simple/
腾讯源:http://mirrors.cloud.tencent.com/pypi/simple
华为镜像源:https://repo.huaweicloud.com/repository/pypi/simple/
pip3.8 install 模块名 -i 源地址
下载报错
1.pip工具版本过低 直接拷贝提示信息里面的更新命令即可
python38 -m pip install --upgrade pip
2.网络波动 关键字是Read timed out
只需要重新下载几次即可 或者切换一个网络稳定一点的
3.有些模块在下载使用之前需要提前配置指定的环境
结合具体情况 百度搜索
openpyxl模块
用于操作excel表格
python中操作excel表格的模块
1.openpyxl
属于近几年比较流行的模块
对03版excel之前的版本不太兼容
2.xlwt、xlrd
同样可以操作excel表
对03版以前的excel兼容性要好与openpyxl 但使用方式较复杂
excel版本的变更
03版之前 excel文件后缀为 .xls
03版之后 excel文件后缀为 .xlsx
如果是苹果本 excel文件后缀为 .csv
openpyxl模块实操
pip install openpyxl
# 创建文件
from openpyxl import Workbook # 导入模块
wb = Wookbook() # 创建excel文件对象
wb1 = wb.create_sheet('sheet1') # 创建一个名为 sheet1 的工作簿
wb2 = wb.create_sheet('sheet2') # 创建一个名为 sheet2 的工作簿
wb1.title = 'sheet111' # 修改工作簿对象 wb1 的名字为 sheet111
wb.save(r'111.xlsx') # 保存excel文件
wb1['A1'] = '这是excelA1的内容' # 可以通过 ['位置'] 的方式在指定位置填写内容
wb1.append(['username', 'password', 'age', 'hobby']) # 也可以通过.append直接添加一行多个数据
# 也可以写算数公示
# wb1['A3'] = '=sum(A1:A2)'
wb.save(r'111.xlsx')
openpyxl模块读取数据
# openpyxl读写数据使用的模块不一样
from openpyxl import Workbook, load_workbook
# wb = Workbook()
# wb1 = wb.create_sheet('红浪漫消费记录', 0)
# wb2 = wb.create_sheet('天上人间消费记录')
# wb3 = wb.create_sheet('白马会所消费记录')
#
#
# wb1.append(['username', 'gender', 'age'])
# wb1.append(['jason', 'male', 18])
# wb1.append(['kevin', 'female', 38])
# wb1.append(['tony', 'male', 58])
# wb1['C5'] = '=AVERAGE(C2:C4)'
#
# wb.save(r'111.xlsx')
wb = load_workbook(r'111.xlsx')
print(wb.sheetnames) # ['红浪漫消费记录', 'Sheet', '天上人间消费记录', '白马会所消费记录']
wb1 = wb['红浪漫消费记录']
# print(wb1.max_row)
# print(wb1.max_column)
# print(wb1['A1'].value)
# print(wb1.cell(row=2, column=2).value)
for i in wb1.rows:
print([j.value for j in i])
# ['红浪漫消费记录', 'Sheet', '天上人间消费记录', '白马会所消费记录']
# ['username', 'gender', 'age']
# ['jason', 'male', 18]
# ['kevin', 'female', 38]
# ['tony', 'male', 58]
# [None, None, '=AVERAGE(C2:C4)']
random随机数模块
import random
random.random() # 返回一个0到1之间的随机小数
random.randint(1, 10) # 返回一个1到10之间的整数 包括1和10
random.randrange(1, 10) # 和randint相似 取得到1取不到10
random.choice(列表) # 随机抽取一个
random.sample(列表, 个数) # 自定义抽取个数
random.shuffle(列表) # 打乱 洗牌
"""面试题:5位验证码 每位可以是大写字母、小写字母、数字"""
code = ''
for i in range(5):
random_int = str(random.randint(0, 9))
random_lower = chr(random.randint(97, 122))
random_upper = chr(random.randint(65, 90))
code += random.choice([random_int, random_lower, random_upper])
print(code) # b36Eh
# 也可以封装 自定义个数
def get_code(n):
code = ''
for i in range(n):
random_int = str(random.randint(0, 9))
random_lower = chr(random.randint(97, 122))
random_upper = chr(random.randint(65, 90))
code += random.choice([random_int, random_lower, random_upper])
return code
code = get_code(10) # 0I2g9lX944
hashlib加密模块
什么是加密
将看得懂的文字(明文) 处理变成看不懂的文字(密文) 的过程
为什么要加密
为了数据的安全
如何判断数据是否加密
加密后的数据一般由无规则的字母、数字、符号组成
加密算法
就是加密所采用的策略 类似编码时按照指定的规范编码
不同加密算法结果不同 复杂度也不同
一般情况下 加密后的结果越长 加密越复杂
常见加密算法
md5 sha系列 hmac base64
import hashlib
md5 = hashlib.md5() # 使用md5加密策略
md5.update(b'123') # 添加明文 数据必须是bytes类型
res = md5.hexdigest() # 获取加密之后的值
print(res) # 202cb962ac59075b964b07152d234b70
# 一般情况下 会对明文进行加盐处理 这样可以使密文有干扰项 安全性有提高
# 加盐处理就是在明文前后添加指定或自己知道他人不容易知道的规范字符
subprocess模块
import subprocess
sub = subprocess.Popen('cccc',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
# stdout执行命令之后正确的返回结果
print(sub.stdout.read().decode('gbk'))
# stderr执行命令报错之后的返回结果
print(sub.stderr.read().decode('gbk')) # error
logging日志模块
模板
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配置
# '购物车记录': {
# 'handlers': ['default','console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
# 'level': 'WARNING',
# 'propagate': True, # 向上(更高level的logger)传递
# }, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
},
}
logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中的配置
# logger1 = logging.getLogger('购物车记录')
# logger1.warning('尊敬的VIP客户 晚上好 您又来啦')
# logger1 = logging.getLogger('注册记录')
# logger1.debug('jason注册成功')
logger1 = logging.getLogger('红浪漫顾客消费记录')
logger1.debug('慢男 猛男 骚男')
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现