请立刻停止,然后...

我在参与不同公司和项目时发现了一些与 Python 相关的问题,这些问题通常令人烦恼、难以维护,而且已经显得过时了。使用以下这些方式,能让你的项目更加优雅。

使用 pyproject.toml

不要再在你的 README.md 文件里写pip install -r requirements.txt 来安装依赖了。虽然 pip 确实可以做到,但我们不推荐这么做。requirements.txt 只是个意外的“标准”。

相反,直接使用 pyproject.toml,它更合理、更现代化,并且 pip 能完全理解它。它还能帮助你定义开发环境和依赖组,避免创建额外的文件如 dev-requirements.txt 和复杂的 CI/CD 管道规则。

使用版本与项目管理工具

我个人偏爱 UVPoetry 也很不错。这些工具都能读取 pyproject.toml 文件,处理依赖管理、构建、在沙盒中运行应用、管理 Python 版本等等。花一小时学习这些工具,能让你少掉不少头疼事。请使用一个虚拟环境(如 venv),以免全局范围的依赖冲突。

顺便提一句,UV 的依赖安装速度比 pip 快得多。

使用类型提示

类型提示非常有助于代码的可读性,也能帮助像 ruffmypy 这样的静态检查工具了解代码逻辑。你的同事也会更喜欢你的代码。

这段代码很难理解:

def do_something(data):
    for x in data:
        for y in data[x]:
            transmute(data[x][y])

但加上类型提示后:

def alter_map(data: Map) -> None:
    """修改二维 map 数据。直接修改传入的对象"""
    for x in data:
        for y in data[x]:
            transmute(data[x][y])

更清晰、直观,尤其是两年后回头看自己的代码。请给函数的所有参数、返回值等添加类型提示。

在函数注释中添加 Raises 部分

虽然有些人可能觉得这是多余的,但添加一个 Raises 部分可以减少代码的意外行为,尤其在维护阶段很有帮助。

from typing import Dict, Any, Optional

def query_db(query: SqlQuery) -> Optional[Dict[str, Any]]:
    """调用数据库。
    
    Args:
        query: 数据库查询对象。
    
    Raises:
        ClientException: 客户端错误。
        TimeoutException: 数据库超时。
        ConnectionException: 网络连接问题。
    
    Returns:
        数据库查询的响应(如果有)。
    """
    pass

这样的注释对开发和维护都很友好。

使用 Pydantic 模型

函数中用多个参数传递不变的数据是一种常见反模式。例如,数据处理管道中环境变量通常只被查一次且不会改变。与其这样操作:

def process_data(env, data, config):
    ...

不如直接定义一个 Pydantic 模型

from pydantic import BaseModel

class EnvConfig(BaseModel):
    env: str
    data: dict
    config: dict

然后只传递一个参数:

def process_data(config: EnvConfig):
    ...

这样不仅有类型检查,还能减少参数传递的复杂性。

代码是不是优雅了许多?

使用格式化工具和静态检查工具

JavaScript 项目几乎已经把 Prettier 当成标准了。在 Python 中,可以使用 Ruff,它以 Black 的格式化标准为基础,速度极快。它不仅能格式化代码,还能检查一些常见问题。

虽然 Ruff 的 linting 不如静态分析工具(如 mypy)全面,但已经足够强大。

以下是可以加入到 pyproject.toml 的一些规则配置:

[tool.ruff]
target-version = "py12"

[tool.ruff.lint]
extend-select = [
  'D', # pydocstyle
  'E', 'W', # pycodestyle
  'F', # pyflakes
  'I', # sort imports
  'UP', # pyupgrade
  'RUF', # ruff 自定义规则
  'SIM', # 简化性规则
  'C90', # 复杂度规则
]

[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.ruff.lint.isort]
combine-as-imports = true
split-on-trailing-commas = false

这些规则可以根据需要自由选择。

使用 Pytest 替代 Unittest

如果有机会,将 unittest 替换为 pytest

它提供了更加简洁的语法和丰富的功能。使用 pytest 不需要像 unittest 那样继承 TestCase 类,只需直接定义测试函数,并用 Python 的原生断言语法(assert)即可。相比 unittestself.assertEqual 等方法,pytest 的断言更加直观,输出也更清晰。

测试文件命名需要以 test_ 开头或以 _test.py 结尾,测试函数名称也需以 test_ 开头。pytest 提供了强大的参数化测试功能,可以通过 @pytest.mark.parametrize 轻松实现多组输入输出的测试。

pytest 还拥有丰富的插件生态,可以扩展测试功能,比如生成测试覆盖率报告或进行性能分析。相比 unittestpytest 更适合快速开发和维护现代项目,尤其是在需要灵活性和扩展性的场景中。

其他建议

  1. orjson 替代内置的 json:性能更高。
  2. 始终使用 f-strings:取代字符串拼接、.format()% 格式化。
  3. pathlib 替代 os.path:更现代化且更具可读性。
  4. click 替代 argparsesys.argv:更强大的命令行参数解析工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值