R开发者Python包开发实战指南

Python包开发:R开发者指南

开发工具选择

最近几个月,我看到很多消息称赞uv工具作为Python环境和依赖管理器。据我理解,uv同时替代了pip、venv,并在某种程度上替代了poetry。它还提供了几个用于包开发的有用快捷方式。

poetry可能是另一个选择,但我还没有机会尝试它。

包创建

在R中,我经常使用usethis::create_package()创建新包。

使用uv,您可以使用以下命令完成相同的操作:

uv init blueskypy --lib

这会创建一个类似于R包的项目结构:

blueskypy/
├── pyproject.toml

├── .gitignore
├── .python-version
└── src/
    └── blueskypy/
        ├── __init__.py
        └── py.typed

R开发者会认出几个熟悉的元素:

  • .gitignore:从版本控制中排除的文件
  • src/:源文件目录(相当于R包中的R/文件夹)
  • pyproject.toml:元数据、依赖项等(相当于DESCRIPTION文件)

其他文件是Python特定的,py.typed.python-version

版本控制设置

在R中,我很少使用usethis::use_git(),更喜欢命令行。

这里采用相同的方法:

git init
git remote add origin repo_url.git
git branch -M main

添加函数及其依赖项

为了与Bluesky API交互,我选择使用requests库。

在R中,我会使用usethis::use_package()

在使用uv的Python中,只需运行:

uv add requests

此命令更新pyproject.toml文件并创建一个uv.lock文件,其中详细说明了项目的所有确切依赖项:

dependencies = [
    "requests>=2.32.5",
]

然后我在src/blueskypy/session.py中添加我的第一个函数(我在Python中找不到相当于usethis::use_r()的功能):

"""Bluesky会话管理模块"""
import requests

def create_session(
    handle=None,
    password=None,
    url="https://bsky.social/xrpc/com.atproto.server.createSession",
):
    """创建Bluesky会话并返回访问JWT。

    Args:
        handle: Bluesky句柄(如果为None,使用BLUESKY_HANDLE环境变量)。
        password: 密码(如果为None,使用BLUESKY_PASSWORD环境变量)。
        url: Bluesky API URL。

    Returns:
        访问JWT。
    """
    # ... 代码 ...
    return "access_jwt"

文档在这里以docstring的形式集成,这是一个与R中roxygen2文档(#' @param等)接近的概念。

在Cursor IDE中,我使用Pylance扩展,它检查docstring的存在并在缺少文档时"抱怨"——这是我希望在R中看到的功能!而Cursor让我可以非常快速地完成它们。

测试和重新加载代码

在R中,我几乎强迫性地使用load_all()在每次修改后重新加载我的包。

在Python中,等效的是"可编辑"安装:

uv pip install -e .

这使得包可用,而无需在每次更改时重新安装。

要运行测试脚本:

uv run script.py

如果您在Quarto笔记本中工作,您可以在不重启内核的情况下强制重新加载修改的模块,这要归功于:

import blueskypy.bluesky_session
import importlib
importlib.reload(blueskypy.bluesky_session)
blueskypy.bluesky_session.create_session()

这使我可以考虑create_session()函数中的代码修改,而无需重启内核。

这是R中devtools::load_all()的Python等效。但我发现这比在R中要繁琐得多。

文档和 vignette

与使用roxygen2标签可以获取文档页面的方式相同,我们用于记录create_session()函数的docstring允许我们为此函数生成文档页面。

原生情况下,文档显示在终端中,显然不可能像在R包中那样以HTML格式简单显示文档。

根据使用的IDE,文档页面也可以通过悬停在函数名称上交互式显示。

添加 vignette

Vignette是比函数文档页面更全面的文档页面。在R中,您可以使用usethis::use_vignette()函数轻松创建vignette。

在Python中,我觉得您需要深入研究sphinx工具,它提供基于Markdown格式编写vignette(所以R用户应该不会太迷茫!)。

内部包数据

在Python中,我没有找到这些文件夹的等效项,但我仍然能够通过创建一个返回用户可操作数据的函数将数据插入包中。

这些数据包含Bluesky帖子的样本。我将一个json文件存储在位于与源代码相同级别的data/文件夹中(我觉得Python在存储包中的文件/文件夹方面比R更宽松)。

最终我有一个load_sample_posts()函数,允许我将这些数据加载到工作环境中。

"""blueskypy包的数据加载工具。"""

import json
from importlib.resources import files

def load_sample_posts():
    """从数据目录加载样本帖子。"""
    data_file = files("blueskypy") / "data" / "sample_posts.json"
    with open(data_file, "r", encoding="utf-8") as f:
        json_content = json.load(f)
    return json_content

调试代码

调试并非包开发特有,但它是任何开发方法中的基本步骤。

在R中,我经常使用browser()debugonce()——两个理解代码行为不可或缺的函数,尤其是在嵌套函数中。

在Python中,最直接的等效是内置的breakpoint()函数,您将其放在要暂停执行的位置。当达到该点时,解释器打开一个交互式会话(由pdb模块管理),允许您检查变量、逐步执行指令和恢复执行。

测试和检查

单元测试放在我手动创建的tests/文件夹中。

我使用pytest运行它们:

pytest tests/

这是R中devtools::test()的等效项。

为了以更全局的方式检查代码和文档质量,我没有找到相当于R中devtools::check()的工具。有时这个工具是我最可怕的噩梦……但大多数时候它是救命稻草!

包安装

本地安装通过以下方式完成:

uv pip install .

结论

作为R开发者,在开发Python包时我并没有完全迷失方向。

结构和组织的逻辑仍然相当相似,即使实践有所不同。

有几个点对我来说似乎不太流畅:

  • 文档:在R中,roxygen2、vignette和pkgdown形成了一个极其高效的生态系统。
  • load_all():Python在reload()和"可编辑"环境之间需要更多的技巧。
  • devtools::check():我没有找到像这样完整和集成的工具。

但总体而言,这次体验让我更好地理解了Python世界,并意识到R在使包开发简单、集成和连贯方面取得了多大的成功。

包源代码可在此处获取(比文章中呈现的功能更多)。

再次强调,请不要犹豫指出我可能犯的错误,或指导我在那些我感到更困难的事情上!
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)或者 我的个人博客 https://blog.qife122.com/
对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值