
pandas 代码库贡献指南编码规范、测试驱动开发与性能基准实战【免费下载链接】pandasFlexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more项目地址: https://gitcode.com/gh_mirrors/pa/pandas本指南基于 pandas 官方开发者文档 contributing_codebase.rst系统梳理向 pandas 代码库提交代码时必须遵循的编码标准、pre-commit 工作流、类型注解约定、测试组织规则与性能基准方法。读者将掌握如何让代码通过 pandas 的 CI 严格检查、如何按规范定位并编写测试、如何运行与并行化测试套件以及如何用 asv 验证性能回归从而高质量地完成一次贡献。代码标准为什么写好代码是硬性要求Writing good code 不只是写出来的内容本身还涉及怎么写。在 pandas 的 :ref:持续集成CIcontributing.ci测试阶段会运行多种工具检查代码的风格错误任何警告都会导致测试失败。因此良好的代码风格是向 pandas 提交代码的前提条件。由于 pandas 拥有大量用户与存量代码开发者还需要尽可能保持向后兼容backwards compatible避免突然改动可能破坏大量用户代码。如果确实需要破坏性变更必须在 pull request 中明确说明原因修改方法签名时要格外谨慎并在需要处添加弃用警告deprecation warnings和对应的 Sphinx 弃用指令。pre-commit是帮助贡献者在提交前自检的关键工具也是下面一节的核心内容。除了格式检查pandas 还通过多种机制保证代码质量例如仓库根目录的 pyproject.toml、.pre-commit-config.yaml 以及 CI 工作流 .github/workflows/code-checks.yml。Pre-commit把风格检查嵌入提交流程CI 会运行诸如ruff、isort、clang-format等代码格式化检查使用 pre-commit hooks。这些检查的任何警告都会导致 CI 失败因此在提交代码前自行运行检查很有帮助。安装并激活 hooks如果你已按照 创建开发环境 的说明完成环境搭建pre-commit应该已经安装。然后在 pandas 仓库根目录执行pre-commit install此后每次git commit都会自动运行全部风格检查无需手动逐个执行同时使用 pre-commit 也能让你更容易跟随项目检查规则的变化保持同步。注意如果确有需要可以用git commit --no-verify跳过这些检查。不安装 hooks 也可以运行检查如果你不想把 pre-commit 纳入工作流仍然可以手动运行检查pre-commit run --files files you have modified pre-commit run --from-refupstream/main --to-refHEAD --all-files第二种命令会针对从upstream/main到HEAD之间变更的所有文件执行检查适合对照主分支校验自己的改动。手动阶段的慢速检查pandas 还配置了一些较慢的 pre-commit 检查它们不会在每次 commit 时运行但会在 CI 中执行。可以手动触发pre-commit run --hook-stage manual --all-files从 .pre-commit-config.yaml 可以看到pyright、mypy、stubtest等检查都被标记为stages: [manual]即只有进入manual阶段才会执行。仓库中的配置还展示了 pandas 维护的众多校验型 hooks例如isort导入排序、clang-formatC/C 格式化作用于pandas/_libs/src与pandas/_libs/includecython-lint、meson-fmt、shellcheck、codespell、sphinx-lint若干项目内自研脚本 hook如 scripts/check_test_imports.pytest-imports、scripts/check_test_naming.py、scripts/validate_min_versions_in_sync.py、scripts/sort_whatsnew_note.py 等。使用建议与已知问题可以定期运行pre-commit gc清理不再使用的仓库repos。如果安装了冲突的virtualenv可能报错使用 conda 时也可能遇到 virtualenv 的 bug可将virtualenv降级到20.0.33解决。如果刚从 upstream 合并了 main 分支pre-commit 依赖的版本可能变化记得先更新开发环境。可选依赖Optional dependencies的导入规范可选依赖例如 matplotlib必须通过私有辅助函数pandas.compat._optional.import_optional_dependency导入。这能保证在依赖缺失时产生一致的错误消息。以 pandas/compat/_optional.py 的实现为例该函数的核心行为是errorsraise默认依赖缺失时抛出带明确安装提示的ImportError版本过旧时同样抛错errorswarn版本过旧时发出UserWarning并返回Noneerrorsignore缺失时返回None不报错min_version参数可覆盖全局最低版本要求。此外所有可选依赖的最低版本集中维护在pandas.compat._optional.VERSIONS字典中同文件 VERSIONS涵盖 matplotlib、scipy、pyarrow、numba、sqlalchemy 等数十个包若导入名与 PyPI 包名不同则通过INSTALL_MAPPING映射如bs4→beautifulsoup4。遵循该规范还需要做到所有使用可选依赖的方法都应包含一个测试断言在缺少该依赖时抛出ImportError库存在时该测试应被跳过所有可选依赖都应记录在文档的安装指南中并在VERSIONS字典中设置最低版本。向后兼容与弃用Deprecation实践pandas 有海量存量代码因此尽可能不要破坏兼容性。如果认为必须破坏请在 pull request 中清楚说明原因。修改方法签名时要谨慎并添加弃用警告。有同签名替代函数时使用deprecate装饰器如果被弃用的函数与替代函数签名一致可以直接使用pandas.util._decorators.deprecatefrom pandas.util._decorators import deprecate deprecate(old_func, new_func, 1.1.0)从源码 pandas/util/_decorators.py 可以看到deprecate内部用wraps包装替代函数在调用时发出警告并自动在 docstring 中注入.. deprecated:: version指令以便未来检测移除它还要求目标函数具有格式正确的 docstring。手动弃用警告 Sphinx 指令如果无法复用装饰器需要手动实现import warnings from pandas.util._exceptions import find_stack_level def old_func(): Summary of the function. .. deprecated:: 1.1.0 Use new_func instead. warnings.warn( Use new_func instead., FutureWarning, stacklevelfind_stack_level(), ) new_func() def new_func(): pass其中find_stack_level()见 pandas/util/_exceptions.py会沿调用栈向上查找第一个不在 pandas 包内部且不在 tests 目录中的帧确保警告的stacklevel指向用户代码而非 pandas 内部避免把警告归因到库自身。除此之外弃用一个参数还需要编写一个新测试断言使用被弃用参数调用时会发出警告更新 pandas 现有的全部测试和代码改用新参数。类型注解Type Hints约定pandas 强烈鼓励使用 PEP 484 风格的类型注解。新开发代码应包含类型注解为既有代码补充注解的 pull request 同样被接受。风格指南类型导入遵循from typing import ...约定pre-commit 检查可能会自动把你的代码重写为现代写法例如用内置list替代typing.List。当类中定义了遮蔽内置名的类变量如str None时mypy 会因 Mypy 1775 描述的问题无法正常解析。防御性做法是先给内置类型起一个无歧义别名再用于注解str_type str class SomeClass2: str: str_type None强烈不鼓励使用cast。当你的推断比静态分析器更聪明时例如自定义推断函数is_numbermypy 无法做出同样的推断参见 mypy #5206此时优先重构代码以取悦静态分析而不是强制castfrom typing import cast from pandas.core.dtypes.common import is_number def cannot_infer_bad(obj: Union[str, int, float]): if is_number(obj): ... else: # 人眼能判断这里只剩 str但 mypy 不行 obj cast(str, obj) # 不加 cast 会报错 return obj.upper() def cannot_infer_good(obj: Union[str, int, float]): if isinstance(obj, str): return obj.upper() else: ...对于自定义类型和推断cast并非完全不可用但应穷尽一切重构手段后再考虑。pandas 专属类型pandas._typingpandas 开发中反复使用的类型集中在pandas._typing模块该模块是私有的仅供 pandas 开发使用。例如很多函数接受dtype参数它既可以是object这样的字符串、np.int64这样的numpy.dtype也可以是pd.CategoricalDtype这样的ExtensionDtype因此可以复用统一的别名from pandas._typing import Dtype def as_type(dtype: Dtype) - ...: ...在 pandas/_typing.py 中可以看到这些别名的定义例如NpDtype: TypeAlias str | np.dtype | type[str | complex | bool | object] Dtype: TypeAlias Union[ExtensionDtype, NpDtype] DtypeArg: TypeAlias Dtype | Mapping[Hashable, Dtype] DtypeObj: TypeAlias Union[np.dtype, ExtensionDtype]该模块还容纳了 path-like、array-like、numeric 等反复出现的概念以及axis这类常用参数的别名。面向用户消费的类型则暴露在pandas.api.typing.aliases见 pandas/api/typing/aliases.py其中FilePath、ArrayLike、Axis、Dtype等大量类型从pandas._typing统一再导出并理想情况下同步到 pandas-stubs 项目。验证类型注解mypy 与 pyrightpandas 使用mypy和pyright对代码库与类型注解做静态分析。修改代码后可在 Python 环境中运行pre-commit run --hook-stage manual --all-files mypy pre-commit run --hook-stage manual --all-files pyright pre-commit run --hook-stage manual --all-files pyright_reportGeneralTypeIssues # 以下命令可能在本地安装的 pandas 版本与本地 git 版本不一致时失败 pre-commit run --hook-stage manual --all-files stubtest警告上述命令使用当前 Python 环境。如果你的包版本比 pandas CI 安装的新/旧常见于mypy或numpy版本不匹配命令可能失败。请按环境搭建说明配置环境或参考 CI 中 Docstring validation, typing, and other manual pre-commit hooks 任务的环境信息来确定版本。从 .pre-commit-config.yaml 可见pyright使用language: node并固定版本如pyright1.1.409还提供了以 pyright_reportGeneralTypeIssues.json 为配置、--level warning的第二种检查mypy与stubtest则直接使用当前环境的python -m mypy/python -m mypy.stubtest。在代码中测试 pandas 的类型注解pandas目前还不是 py.typedPEP 561库本地将 pandas 声明为 py.typed 的主要目的是测试和改进 pandas 内置的类型注解。可以这样实验python -c import pandas; import pathlib; (pathlib.Path(pandas.__path__[0]) / py.typed).touch()py.typed文件的存在会向类型检查器发出pandas 已是 py.typed 库的信号使检查器感知随 pandas 分发的类型注解。持续集成让构建全绿pandas 的测试套件会在你提交 pull request 后自动运行在 GitHub Actions 持续集成服务上。若想在提交前就在自己的分支上运行测试套件需要将 CI 服务接入你的 GitHub 仓库。当所有构建通过green build时pull request 才被考虑合并若有测试失败会显示红色 X可点击查看具体的失败测试。从图中可以看到 pandas 的 CI 包含了CI / Web and docs、CI / Test experimental data manager (...)等多项工作流以及codecov/patch和codecov/project项目覆盖率 93.25%目标 82.00%等覆盖率检查——这正是下一节 TDD 强调覆盖率的原因。测试驱动开发TDDpandas 非常重视测试强烈鼓励贡献者拥抱测试驱动开发开发循环很短——先写一个最初失败的自动化测试来定义期望的改进或新功能再写通过该测试的最少代码。也就是说在写任何代码之前先写测试。测试通常可以取自原始 GitHub issue但总是值得考虑额外的使用场景并编写相应测试。pandas 用代码覆盖率来理解被测代码的比例鼓励你新增或修改的代码都有测试覆盖参见 Codecov 覆盖率看板。添加测试是代码提交到 pandas 后最常见的评审请求因此养成提前写测试的习惯非常值得。测试放哪里位置判断规则所有测试都应放在对应包的tests子目录中。可以用 IDE 的搜索功能或终端里的git grep定位方法被调用的测试文件git grep function_name(理想情况下一个测试应有且只有一个明显的位置。以下是官方的规则速查对应pandas/tests/下的结构只依赖pd._libs.tslibs→tests.tslibs注意tests.tslibs中任何文件不得导入pd._libs.tslibs之外的 pandas 模块、tests.scalar、tests.tseries.offsets只依赖pd._libs→tests.libs、tests.groupby.test_libgroupby算术或比较方法→tests.arithmetic通过box_with_arrayfixture 共享测试 DataFrame/Series/Index/ExtensionArray 行为、tests.frame.test_arithmetic、tests.series.test_arithmetic归约方法min、max、sum、prod……→tests.reductions共享行为测试、tests.frame.test_reductions、tests.series.test_reductions、tests.test_nanops索引方法最难定位因为常同时测试多个方法A) 仅测试 Index 方法如Index.get_loc、Index.get_indexer→tests.indexes.test_indexing、tests.indexes.fooindex.test_indexing文件内应有方法专属测试类如TestGetLoc大多数情况不需要 Series/DataFrameB) 测试xs、where、take、mask、lookup、insert等非__getitem__/__setitem__→tests.frame.indexing.test_methodname、tests.series.indexing.test_methodnameC) 测试loc、iloc、at、iat→tests.indexing.test_loc、tests.indexing.test_iloc、tests.indexing.test_at、tests.indexing.test_iatD) 测试__getitem__/__setitem__→tests.series.test_getitem、tests.series.test_setitem、tests.frame.test_getitem、tests.frame.test_setitem。若一个测试同时覆盖多个相似方法应基于底层方法或 bug 的实际位置定位。例如下面的测试同时覆盖了ser[[3, 4]]与ser.loc[[3, 4]]由于Series.__getitem__内部会调用Series.loc.__getitem__它本质上是测试loc.__getitem__因此应放入tests.indexing.test_locimport pandas as pd import pandas._testing as tm def test_getitem_listlike_of_ints(): ser pd.Series(range(5)) result ser[[3, 4]] expected pd.Series([2, 3]) tm.assert_series_equal(result, expected) result ser.loc[[3, 4]] tm.assert_series_equal(result, expected)DataFrame/Series 方法绘图方法 →tests.plottingIO 方法 →tests.io含to_string但__repr__在tests.frame.test_repr/tests.series.test_repr否则 →tests.series.methods.test_mymethod、tests.frame.methods.test_mymethod能通过frame_or_seriesfixture 在两者间共享的测试按惯例放在tests.frameIndex 方法不依赖 Series/DataFrame→tests.indexespandas 内置 ExtensionArrayCategorical、DatetimeArray、TimedeltaArray、PeriodArray、IntervalArray、NumpyExtensionArray、FloatArray、BoolArray、StringArray→tests.arrays面向所有 ExtensionArray 子类EA Interface→tests.extension。测试中的导入规范顶层 pandas 命名空间的对象通过pd访问而不是直接导入import pandas as pd ser pd.Series([1, 2, 3])其余对象从定义它的模块导入例如import pandas._testing as tm或from pandas.core.dtypes.common import is_integer_dtype。test-importspre-commit hook对应 scripts/check_test_imports.py会检查测试文件不得直接从pandas命名空间导入。pytest 惯用法pandas 现有测试结构大多是类风格的但项目更偏好基于 pytest 的函数式风格class TestReallyCoolFeature: def test_cool_feature_aspect(self): pass def test_really_cool_feature(): pass推荐惯用法函数式测试命名为def test_*且只接受 fixture 或参数作为参数标量与真值测试使用裸assert比较结果使用tm.assert_series_equal(result, expected)与tm.assert_frame_equal(result, expected)多场景用pytest.mark.parametrize预期失败用pytest.mark.xfail预期永远不会通过用pytest.mark.skip需要特定标记的用例用pytest.param多个测试共享 setup 对象用pytest.fixture。警告不要使用pytest.xfail区别于pytest.mark.xfail因为它会立即中断测试且不检查测试是否真的失败若确实需要这种立即退出行为请用pytest.skip。对于已知失败但失败方式无需捕获的测试用pytest.mark.xfail常见于存在 bug 的行为或未实现的功能。若失败具有 flaky 行为使用strictFalse但这是极不推荐的最后手段。尽量在测试收集阶段用装饰器pytest.mark.xfail或pytest.param标记若需对涉及多参数、fixture 或两者组合的用例做 xfail只能在测试阶段用requestfixturedef test_xfail(request): mark pytest.mark.xfail(raisesTypeError, reasonIndicate why here) request.applymarker(mark)xfail 不得用于用户传参非法导致的失败。这类测试必须用pytest.raises验证正确的异常类型与错误消息。测试警告用tm.assert_produces_warning作为上下文管理器检查代码块是否产生警告并用match指定警告消息with tm.assert_produces_warning(DeprecationWarning, matchthe warning message): pd.deprecated_function()期望产生警告时两个参数都必须提供极少数消息确实无法断言时传matchNone。若某段代码不应产生警告则传入Falsewith tm.assert_produces_warning(False): pd.no_warning_function()如果测试会发出警告但你并不真正测试该警告本身例如它未来会被移除或是在匹配第三方库的行为用pytest.mark.filterwarnings忽略pytest.mark.filterwarnings(ignore:msg:category) def test_thing(self): pass测试异常用pytest.raises上下文管理器指定具体的异常子类绝不使用Exception并通过match匹配异常消息with pytest.raises(ValueError, matchan error): raise ValueError(an error)涉及文件的测试temp_filepytest fixture 会创建一个临时的Pathlib对象用于测试def test_something(temp_file): pd.DataFrame([1]).to_csv(str(temp_file))临时文件保留策略可参考 pytest 文档。涉及网络连接的测试单元测试不应访问公网数据集网络不稳定且无法控制远端服务器。应使用pytest-localserver插件提供的httpserverfixture 配合合成数据模拟交互pytest.mark.network pytest.mark.single_cpu def test_network(httpserver): httpserver.serve_content(contentcontent) result pd.read_html(httpserver.url)完整示例以下是一个自包含的测试文件pandas/tests/test_cool_feature.py展示了多种推荐特性记得为每个新测试注释 GitHub issue 编号import pytest import numpy as np import pandas as pd pytest.mark.parametrize(dtype, [int8, int16, int32, int64]) def test_dtypes(dtype): assert str(np.dtype(dtype)) dtype pytest.mark.parametrize( dtype, [float32, pytest.param(int16, markspytest.mark.skip), pytest.param(int32, markspytest.mark.xfail( reasonto show how it works))]) def test_mark(dtype): assert str(np.dtype(dtype)) float32 pytest.fixture def series(): return pd.Series([1, 2, 3]) pytest.fixture(params[int8, int16, int32, int64]) def dtype(request): return request.param def test_series(series, dtype): # GH issue_number result series.astype(dtype) assert result.dtype dtype expected pd.Series([1, 2, 3], dtypedtype) tm.assert_series_equal(result, expected)运行结果如下注意test_mark[int16]被 SKIPPED、test_mark[int32]被 xfail((pandas) bash-3.2$ pytest test_cool_feature.py -v test session starts platform darwin -- Python 3.6.2, pytest-3.6.0, py-1.4.31, pluggy-0.4.0 collected 11 items tester.py::test_dtypes[int8] PASSED tester.py::test_dtypes[int16] PASSED tester.py::test_dtypes[int32] PASSED tester.py::test_dtypes[int64] PASSED tester.py::test_mark[float32] PASSED tester.py::test_mark[int16] SKIPPED tester.py::test_mark[int32] xfail tester.py::test_series[int8] PASSED tester.py::test_series[int16] PASSED tester.py::test_series[int32] PASSED tester.py::test_series[int64] PASSED参数化后的测试可通过测试名定位例如用-k int8只选择匹配int8的测试((pandas) bash-3.2$ pytest test_cool_feature.py -v -k int8 test session starts platform darwin -- Python 3.6.2, pytest-3.6.0, py-1.4.31, pluggy-0.4.0 collected 11 items test_cool_feature.py::test_dtypes[int8] PASSED test_cool_feature.py::test_series[int8] PASSED运行测试套件可以在 Git clone 内直接运行无需安装 pandaspytest pandas注意若少量测试不过可能不是 pandas 安装的问题。部分测试如某些 SQLAlchemy 测试需要额外配置有些可能因未固定版本的库发布新版本而失败有些在并行运行时可能 flaky。只要能从本地构建版本导入 pandas安装通常没问题就可以开始贡献了。更常见的做法是先用子集测试pytest pandas/path/to/test.py -k regex_matching_test_name或使用以下结构之一pytest pandas/tests/[test-module].py pytest pandas/tests/[test-module].py::[TestClass] pytest pandas/tests/[test-module].py::[TestClass]::[test_method]用 pytest-xdist 并行加速pytest-xdist已包含在pandas-dev环境中可在多核机器上加速本地测试。用-n指定并行核心数或用auto使用全部核心# 使用 4 个核心 pytest -n 4 pandas # 使用全部可用核心 pytest -n auto pandas更高级的用法示例pytest pandas -n 4 -m not slow and not network and not db and not single_cpu -r sxX-m标记可跳过部分测试slow耗时长的测试秒级而非毫秒级network需要网络连接的测试db需要数据库mysql 或 postgres的测试这些测试在没有数据库时会自行跳过所以-m not db只是为了省去检查数据库的开销single_cpu只能在单 CPU 上运行的测试。如与你相关还可以启用arm_slow在 arm64 架构上耗时的测试。这些标记定义在 pandas/conftest.py 的PANDAS_MARKERS列表中并通过pytest_configure注册到 pytest如果想知道是否新增了感兴趣的标记可以查看该列表。-r报告标志会显示简短汇总sskippedxxfailedXxpassed是可选信息。并行化能显著缩短提交前的本地测试时间。设置随机种子以便复现如果遇到难以定位的结果先设置种子再运行并打开 bug 报告便于复现。Windows 示例set PYTHONHASHSEED314159265 pytest pandas -n 4 -m not slow and not network and not db and not single_cpu -r sxXUnix 示例export PYTHONHASHSEED314159265 pytest pandas -n 4 -m not slow and not network and not db and not single_cpu -r sxX在已安装的 pandas 上运行导入 pandas 后也可以直接运行pd.test()运行性能基准套件性能很重要值得考虑你的代码是否引入了性能回归。pandas 正在迁移到 asv 基准airspeed velocity以方便监控关键操作的性能。所有基准都在 asv_bench 目录中按功能分门别类存放如algorithms.py、groupby.py、join_merge.py、io/parsers.py、tslibs/timestamp.py等结果可在线查看。要使用 asv 的全部特性需要conda或virtualenv。安装 asvpip install githttps://github.com/airspeed-velocity/asv对比两个版本进入asv_bench/目录后运行asv continuous -f 1.1 upstream/main HEAD把HEAD替换为你正在开发的分支名并报告变化超过 10% 的基准。该命令默认用conda创建基准环境改用 virtualenv 则写asv continuous -f 1.1 -E virtualenv upstream/main HEAD-E virtualenv选项应加到所有运行基准的 asv 命令上默认值定义在 asv_bench/asv.conf.json 中当前该配置使用rattler环境类型并声明了branches: [main]与丰富的依赖矩阵。只跑子集基准完整基准套件可能耗时一整天取决于硬件与资源利用率。通常只需把部分结果贴进 pull request证明改动未引入意外回归。用-b加正则表达式运行特定基准# 只运行 asv_bench/benchmarks/groupby.py 中的基准 asv continuous -f 1.1 upstream/main HEAD -b ^groupby # 只运行 groupby.py 中 GroupByMethods 这一个基准组用 . 分隔 asv continuous -f 1.1 upstream/main HEAD -b groupby.GroupByMethods用当前环境运行如果你没有 virtualenv 或 conda也可以使用当前 Python 环境中已安装的 pandas 版本运行基准。in-place 构建需要设置PYTHONPATH例如PYTHONPATH$PWD/.. asv [remaining arguments]。使用现有 Python 环境运行asv run -e -E existing或指定特定解释器asv run -e -E existing:python3.6这会显示基准的 stderr并使用$PATH中的本地python。关于如何编写基准以及 asv 的更多用法可参考 asv 文档。为你的代码编写文档代码变更应反映在发布说明doc/source/whatsnew/vx.y.z.rst中该目录保存了从 v0.4.x 到 v3.x 的全部历史发布记录当前开发版本对应最新的版本文件。在其中添加条目来记录你的修复、增强或不可避免的破坏性变更并务必包含 GitHub issue 编号:issue:1234其中1234是 issue/pull request 编号条目应使用完整句子和规范语法。提及 API 时按需使用 Sphinx 的:func:、:meth:或:class:指令并非所有公共 API 都有文档页理想情况下只在链接能解析时添加。可参考旧版本的发布说明寻找类似示例。Bugfix将条目添加到对应的 bugfix 小节避免放进Other小节仅在罕见情况下才放。描述应尽可能简洁包含用户如何遇到该 bug 以及 bug 本身的迹象如 produces incorrect results、incorrectly raises必要时说明新行为。Enhancement通常需要在现有文档中补充使用示例。为了让用户知道功能何时加入使用versionadded指令.. versionadded:: 2.1.0这会在放置指令处显示New in version 2.1.0文本。新增函数、方法或新的关键字参数时也应将该指令写入 docstring。完成以上所有步骤后你的改动就可以提交 pull request 了。核心流程可以概括为pre-commit install让风格检查自动运行 → 编写先失败的测试 → 最小实现让测试通过 → 运行pre-commit run --hook-stage manual --all-files做类型与慢速检查 →pytest -n auto pandas跑全量测试 → 用asv continuous验证无性能回归 → 在发布说明中记录变更。这套工作流既能保证 pandas 的代码质量与向后兼容也能让你的贡献快速通过 CI 评审。【免费下载链接】pandasFlexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more项目地址: https://gitcode.com/gh_mirrors/pa/pandas创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考