C++开发(五)
C++和Python开发(五)
最后整理些细碎的内容,就把和GPT的聊天都删掉了,最近在这些上投入了太多精力,需要做些其他事情缓解一下了。
Pytest
pytest中的tests目录下可以新建一个conftest.py文件,不同的test_xx.py都会先运行这个文件,类似于GoogleTest中的夹具。
import
Python的import确实还有很多地方我没弄明白。from xx import yy中,xx必须是一个实际存在的东西,不论是一个目录(包)还是一个文件(模块),纯粹导入命名空间是不行的。
setup
可以通过环境变量,让用户自行决定是否安装某些扩展模块。这可以通过扩展build_ext来实现:
1 | class CMakeBuild(build_ext): |
pip和python setup.py
pip install .
- 依赖管理:
pip会自动管理依赖关系,并确保所有依赖项都被正确安装。如果你的项目中定义了install_requires选项(在setup.py中),pip会确保这些依赖项在安装你的包之前被安装。 - 使用
wheel包: 如果可能,pip会尝试使用已经构建好的wheel文件(.whl)来安装包,这通常比从源码构建快得多。如果没有现成的wheel,pip也可以从源码构建并安装。 - 隔离环境: 默认情况下,
pip会使用一个临时的隔离环境来执行构建,这意味着构建过程中使用的依赖项不会污染全局的Python环境。可以通过--no-build-isolation选项来禁用这一行为。 - 自动安装
setuptools和wheel:pip会自动确保setuptools和wheel这些构建工具已经安装。 - 更多高级功能:
pip提供了许多额外的功能,比如--upgrade(升级已安装的包)、--target(指定安装目录)等。
python setup.py install
- 手动安装: 直接调用
setup.py的install命令,不会管理依赖项。这意味着你需要手动确保所有依赖项都已经安装。 - 不使用
wheel:setup.py install直接从源码构建并安装包,而不是使用wheel文件。因此,安装速度可能会更慢,尤其是对于需要编译的扩展模块。 - 无隔离环境:
setup.py install不会在隔离的环境中运行,所有构建和安装操作都直接在当前的 Python 环境中进行。这可能会导致依赖项之间的冲突,或者污染全局的 Python 环境。 - 逐步过时:
python setup.py install的使用在逐渐减少,因为pip提供了更多的功能和更好的依赖管理。官方文档也建议使用pip来进行安装。
关于inplace
当运行 python setup.py build_ext 来构建 Cython 模块后,生成的 .pyd(Windows)或 .so(Linux/Mac)文件通常会被放置在一个特定的构建目录中。默认情况下,这些文件可能并没有直接放在你的源代码目录中,而是被放置在一个名为 build 的子目录里。
查看
build目录:默认情况下,构建的模块通常位于
build/lib.<platform>目录下。例如,在 Windows 上可能是build/lib.win-amd64-3.8(假设你使用的是 Python 3.8)。你可以使用以下命令来查看构建目录:
1
ls build/
使用
--inplace选项:如果你希望生成的模块直接放在源代码目录(与
.pyx文件相同的目录)中,可以在运行build_ext时使用--inplace选项:1
python setup.py build_ext --inplace
这样生成的
.pyd文件将直接出现在源代码目录中,与你的.pyx文件在同一个位置。
指定构建目录:
- 如果你希望构建的模块放在一个特定的目录中,可以在
setup.py中使用ext_modules和Extension类的参数build_dir来指定。
- 如果你希望构建的模块放在一个特定的目录中,可以在
关于cython构建
cython的构建比较麻烦,在命令行里直接用cythonize,至少在Win下很难导入Numpy的头文件。在setup.py里改写build_ext的run方法,cython的构建就会一直出错。现在看来比较好的方式就是,ext_modules中只放置cython的模块,重写build_ext后,调用super().run(),保证cython模块的正常构建。其他模块则在之后cmake手动构建,但这些模块都不放入到ext_modules中。构建出来的文件,不需要手动改写RECORD文件注册,直接放到对应的package_data参数中就可以了。这样的方式目前来看是可行的,而且干净的。
关于相对导入
Python的相对导入只能是一个大包下面的包或者模块间相对导入,外部包间是不支持的。