本文介绍python的标准库。python标准库是python自带的,无需手动安装。
想要了解python如何实现自动管理文件,自动处理zip、csv、json文件,了解sqlite的用法、电子邮件的发送,以及正确使用时间格式、随机成复杂密码,并使用命令行参数或运行外部程序,您只需阅读本文就能了解。
Paths
文件和目录的操作是程序开发中常用的场景,Path类可以很好地完成这个工作。
from pathlib import Path
Path(r”c:\Program Files\Microsoft”)
# 使用绝对路径,前面加 r 表示原样,这样不用加转义字符了
Path(“/usr/local/bin”)
Path() # 当前目录
Path(“ecommerce/__init__.py”) # 相对路径
Path()/”ecommerce”/”__init__.py” # 合并路径,结果与上一行代码一样
Path.home() # 取得用户主目录
可以google搜索”python3 pathlib”查看详细
继续:
path = Path(“ecommerce/__init__.py”)
print(path.exists()) # True
print(path.is_file()) # True
print(path.is_dir()) # False
print(path.stem) # 获取不包含最后扩展名的文件名,__init__
print(path.suffix) # 获取扩展名, .py
print(path.parent) # ecommerce
path = path.with_name(“file.txt”)
# 将文件改名,仅生成对象,实际文件未作修改
path.absolute() # 绝对路径
path = path.with_suffix(“.txt”)
# 修改扩展名,也是仅生成对象,实际文件未修改
目录操作
目录常用方法,看名字就显而易见。
path = Path(“ecommerce”)
print(path.exists()) # 查目录是否存在
path.mkdir() # 创建目录
path.rmdir() # 删除目录
path.rename(“ecommerce2”) # 改名
目录遍历:
path = Path(“ecommerce”)
for p in path.iterdir():
print(p)
# iterdir方法产生生成器对象,之前在列表推导中提到到生成器对象
# 它不会全在内存中生成,用到时再生成,适合用于目录下有大量文件的情形下
# 如果目录下的文件和文件夹不多,可以使用列表推导生成列表
paths = [p for p in path.iterdir()]
print(paths)
我们看到输出是 PosixPath(‘ecommerce/shopping’)这样列表项,PosixPath表示是Linux文件。如果是 windows的话,则是 WindowsPath。
过滤只列出目录:
paths = [p for p in path.iterdir() if p.is_dir()]
iterdir()很好用,不过有局限:一是不能用模式搜索;二是不能递归,比如列出子文件夹下的文件。
可以用glob代替,下面的代码将列出目录下的所有py文件
py_files = [p for p in path.glob(“*.py”)]
glob不能递归,而 rglob则可以:
py_files = [p for p in path.rglob(“*.py”)]
文件操作
基本操作:
from pathlib import Path
from time import ctime
path = Path(“ecommerce/__init__.py”)
print(path.exists())
path.rename(“ecommerce/init.txt”) # 修改文件名
path.unlink() # 删除链接或文件
print(path.stat())
# 输出 文件信息
# os.stat_result(st_mode=33188, st_ino=15849392, st_dev=16777220,
# st_nlink=1, st_uid=501, st_gid=20, st_size=0, st_atime=1653210238,
# st_mtime=1653210238, st_ctime=1653210238)
# 我们可以转换成人类能读懂信息,比如创建时间st_ctime
print(ctime(path.stat().st_ctime))
读取文件:
path.read_bytes()
path.read_text()
# 如果用内置open函数会很麻烦,
# with open(“__init__.py”) as file:
# …
# 而用read_bytes 和 read_text 这一切都自动完成。
写文件:
path.write_bytes(data)
path.write_text(“test”)
复制文件:
source = Path(“ecommerce/__init__.py”)
target = Path()/”__init__.py”
target.write_text(source.read_text())
这种方法稍显麻烦,可以使用shutil模块的copy方法。
import shutil
…
shutil.copy(source, target)
# 这种方法更干净高效
使用ZIP文件
打包写入zip文件:
from pathlib import Path
from zipfile import ZipFile
with ZipFile(“files.zip”, “w”) as zip:
for path in Path(“ecommerce”).rglob(“*.*”):
zip.write(path)
# 打包ecommerce文件夹为 files.zip
# rglob(“*.*”)表示递归获取所有文件夹和文件
# with 简化操作,否则要捕捉错误等操作
读zip文件:
from zipfile import ZipFile
with ZipFile(“files.zip”) as zip:
print(zip.filelist)
info = zip.getinfo(“ecommerce/__init__.py”)
# 从上一步查看得到文件名
print(info.file_size) # 查原文件大小
print(info.compress_size) # 查压缩后大小
解压缩:
with ZipFile(“files.zip”) as zip:
zip.extractall(“extract”)
# 提取所有文件到“extract”文件夹
使用CSV文件
写:
import csv
with open(“data.csv”, “w”) as file:
writer = csv.writer(file)
writer.writerow([“transaction_id”, “product_id”, “price”])
writer.writerow([1000, 1, 5])
writer.writerow([1001, 2, 15])
# 生成一个data.csv文件
读:
import csv
with open(“data.csv”) as file:
reader = csv.reader(file)
print(list(reader))
# 输出 [[‘transaction_id’, ‘product_id’, ‘price’], [‘1000’, ‘1’, ‘5’], [‘1001’, ‘2’, ’15’]]
# 每一项都是字符串,需要处理数字、浮点数的话,需要转换
或循环输出:
for row in reader:
print(row)
# 如果已使用了 list(reader)读取,再执行该for循环将输出空,因为文件已读到结尾。
JSON转换
转成json格式:
import json
from pathlib import Path
movies = [
{“id”: 1, “title”: “终结者”, “year”: 1989},
{“id”: 2, “title”: “幼儿园特警”, “year”: 1993},
]
data = json.dumps(movies) # 输出json格式
Path(“movies.json”).write_text(data) # 保存 movies.json文件
加载json,转回ptyhon的数据结构:
import json
from pathlib import Path
data = Path(“movies.json”).read_text()
movies = json.loads(data)
# 返回字典列表
print(movies)
使用SQLite数据库
SQLite是一个简单的数据库。
可以 google搜索 db browser for sqlite,下载相应的工具
新建db.sqlite3文件,并创建表movies,字段分别为it,title,year。
写数据库:
import sqlite3
import json
from pathlib import Path
movies = json.loads(Path(“movies.json”).read_text())
# 读取json文件并存储到字典列表 movies中
with sqlite3.connect(“db.sqlite3”) as conn:
command = “INSERT INTO movies VALUES(?,?,?)”
for movie in movies:
conn.execute(command, tuple(movie.values()))
# tuple函数是将Values变成元组
conn.commit
# 事先要建好movies表,否则出错
读数据库:
with sqlite3.connect(“db.sqlite3”) as conn:
command = “SELECT *FROM movies”
cursor = conn.execute(command)
# 游标curson是可迭代对象,使用for循环获取各条记录
for row in cursor:
print(row)
# 输出结果是:
# (1, ‘终结者’, 1989)
# (2, ‘幼儿园特警’, 1993)
# for语句也可改成用fetchall获取
movies = cursor.fetchall()
print(movies)
# 输出 [(1, ‘终结者’, 1989), (2, ‘幼儿园特警’, 1993)]
使用时间戳 time
python中处理时间有2个模块:time和datetime。
time是一个时间戳一串数字,从1970-1-1年开始计算秒的总数;datetime则是有有年份、月份、日期等。
本小节先讲time。示例计算程序执行时间。
import time
def send_emails():
for i in range(10000):
pass
start = time.time()
send_emails()
end = time.time()
duration = end-start
print(duration)
# 类似于timeit的功能,前面讲异常时提到过
# 在我的电脑输出是 0.0003070831298828125
使用datetime
from datetime import datetime
import time
dt1 = datetime(2022, 1, 1)
dt2 = datetime.now()
dt = datetime.strptime(“2022/01/01”, “%Y/%m/%d”)
# 将字符串改变成时间对象
dt = datetime.fromtimestamp(time.time())
# 时间戳转成时间对象
print(f”{dt.year}/{dt.month}/{dt.day}”)
# 格式化输出2022/5/23
print(dt.strftime(“%Y/%m/%d”))
# strftime用于将时间对象转成字符串,输出 2022/05/23
# 比较
print(dt2 > dt1) # True
使用时间增量 timedelta
from datetime import datetime, timedelta
dt1 = datetime(2022, 1, 1)+timedelta(days=1, seconds=1000)
print(dt1)
# 输出 2022-01-02 00:16:40
dt2 = datetime.now()
duration = dt2-dt1
print(duration)
# 输出 141 days, 17:53:04.472024
print(“days”, duration.days) # 天数
print(“seconds”, duration.seconds) # 除天数之后的秒数
print(“total_seconds”, duration.total_seconds()) # 折算成总秒数
产生随机值
import random
import string
print(random.random()) # 产生0-1之间的一个随机数
print(random.randint(1, 10)) # 产生1-10之间的一个整数
print(random.choice([1, 2, 3, 4])) # 选择一个数
print(random.choices([1, 2, 3, 4], k=2)) # 随机选择2个数
print(
“,”.join(random.choices(“abcdefghi”, k=4))
)
# 随机生成a-i之间的一个密码,用 , 连接
print(
“”.join(random.choices(string.ascii_letters +
string.digits + string.punctuation, k=12))
)
# 随机生成一个12位的强密码
# 随机改变顺序
numbers = [1, 2, 3, 4]
random.shuffle(numbers)
print(numbers)
打开浏览器
import webbrowser
webbrowser.open(“https://www.baidu.com”)
发送电子邮件
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from pathlib import Path
import smtplib
message = MIMEMultipart()
message[“from”] = “kelemi001@qq.com”
message[“to”] = “kelemi@zj.gov.cn”
message[“subject”] = “This is a test.”
message.attach(MIMEText(“Body”, “plain”))
# plain表示纯文本,也可以用”html”表示html
message.attach(MIMEImage(Path(“kelemi.jpeg”).read_bytes()))
# 附加了图片
with smtplib.SMTP_SSL(‘smtp.qq.com’, 465) as smtp:
smtp.login(“kelemi001@qq.com”, “bjepgdcwjrkjbidjikkkkkkggg”)
smtp.send_message(message)
print(“Sent…”)
上述方法一开始就创建安全连接SSL,端口用465。有些先进的邮箱支持先创建不安全连接,后续再创建安全连联,如gmail,可以使用不加密的smtplib.smtp方法,后再调用加密starttsl。
with smtplib.SMTP(host=’smtp.gmail.com’, port=587) as smtp:
# 开始用smtp方法不加密,gmail端口是587
smtp.ehlo() # 先询问
smtp.starttls() # 再加密
smtp.login(“kelemi@gmail.com”, “my_password”)
smtp.send_message(message)
print(“Sent…”)
模板
创建一个template.html文件:
在vscode中,输入!再按tab,自动生成html框架,再在body部分输入:
Hi $name, this is a test.
注意美元符号开头表示变量。template.html内容如下:
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″ />
<meta http-equiv=”X-UA-Compatible” content=”IE=edge” />
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″ />
<title>Document</title>
</head>
<body>
Hi $name, this is a test.
</body>
</html>
再在代码中替换变量:
from string import Template
from pathlib import Path
template = Template(Path(“template.html”).read_text())
print(
template.substitute({“name”: “kelemi”})
)
# 模板中的name将由kelemi代替
# 除了使用字典,也可传递关键字参数,效果是一样的。
print(
template.substitute(name=”kelemi”)
)
命令行参数
sys.argv可以查看命令行参数。
import sys
print(sys.argv)
# 如果执行 python3 -a -b -c
# 输出 [‘app.py’, ‘-a’, ‘-b’, ‘-c’]
# 第一个列表项是应用程序本身
来看个简单的示例,要求用户提供密码参数。
import sys
if len(sys.argv) == 1:
print(“USAGE:python3 app.py <password>”)
else:
password = sys.argv[1]
print(“Password”, password)
运行外部程序
运行外部程序并获得输出,这对自动化任务是有用的。用的是subprocess模块,使用subprocess.run()方法。有些python教程使用的subprocess模块的其它方法如call,check_all,check_output,popen等方法一般不用了,属过时的方法。
import subprocess
completed = subprocess.run([“ls”, “-l”])
# 终端将显示输出
print(completed.args) # [‘ls’, ‘-l’]
print(completed.returncode) # 0
print(completed.stderr) # None
print(completed.stdout) # 没捕捉显示为None
有时候需要获取输出并进行下一步操作,刚设置 capture_output为True。
completed = subprocess.run([“ls”, “-l”], capture_output=True)
# capture_output=True表示捕捉标准输出,终端不再显示
print(completed.stdout)
# 能看到已捕捉输出,b’total 112\n…
# 前面是二进制输出,前面有个b
# 如果需要文本输出,传递关键字参数 text=True 即可
completed = subprocess.run([“ls”, “-l”], capture_output=True, text=True)
运行另一个python 脚本:
completed = subprocess.run([“python3”, “other.py”],
capture_output=True, text=True)
# 运行另外一个python程序,属于另外一个进程,不同内存空间,与import是不同的
异常捕捉:
执行外部命令如果返回非0,且参数check=True的话,会抛出异常需要进行捕捉。
import subprocess
try:
completed = subprocess.run(
[“false”], capture_output=True, text=True, check=True
# check=True 在返回非0的情况下将抛出异常
)
except subprocess.CalledProcessError as ex:
print(ex)
# 输出 Command ‘[‘false’]’ returned non-zero exit status 1.
小结
本文介绍了python的标准库常用的使用场景,包括文件、目录的操作,ZIP文件、csv文件、json文件的使用方法,sqlite的使用,时间,随机数,浏览器的打开,发送电子邮件,模板用法,以及命令行参数及运行外部程序,内容非常丰富。
下一节计划讲解python包的安装、发布以及依赖管理,并介绍python虚拟环境的搭建。近段时间事情较多,更新可能会放慢,敬请期待。