使用Boost.Python封装C++类时触发TypeError:__init__应返回None而非'NoneType'
解决Boost.Python中
__init__() should return None, not 'NoneType'错误 问题分析
你碰到的这个错误是Boost.Python开发里非常典型的版本不匹配问题:编译扩展库时链接的Python版本,和运行代码时使用的Python版本不一致。从你的CMake输出能看到,编译时用的是Python 2.7(found version "2.7.16"),但你运行Python代码时大概率用了Python 3环境,这种版本错位会导致底层类型系统不兼容,从而抛出这个看起来有点奇怪的返回值错误。
另外,你的CMake脚本在版本检测逻辑上有冗余,也容易引发版本匹配问题,这也是需要调整的点。
解决方案
1. 先确认编译与运行的Python版本一致
先检查你运行Python代码时用的是哪个版本:
# 查看当前默认Python路径 which python # 或者检查Python3的路径 which python3
如果运行时用的是Python3,那必须修改CMake脚本,强制指定用Python3编译扩展库。
2. 修复CMake脚本的版本检测逻辑
现有脚本的跨平台版本检测过于繁琐,容易出错,我们可以简化并明确指定Python版本,比如强制使用Python3:
cmake_minimum_required(VERSION 3.13) project(p1) set(CMAKE_CXX_STANDARD 11) # 明确指定优先查找Python3 set(Python_ADDITIONAL_VERSIONS 3.6 3.7 3.8 3.9) find_package(PythonInterp 3 REQUIRED) find_package(PythonLibs 3 REQUIRED) # 匹配对应版本的Boost.Python组件 if(UNIX AND NOT APPLE) find_package(Boost COMPONENTS python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR} REQUIRED) else() # macOS下Boost的Python组件命名通常是python3x格式,比如python37 find_package(Boost COMPONENTS python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR} REQUIRED) endif() # 打印检测信息,确认版本匹配 message(STATUS "PYTHON_LIBRARIES = ${PYTHON_LIBRARIES}") message(STATUS "PYTHON_EXECUTABLE = ${PYTHON_EXECUTABLE}") message(STATUS "PYTHON_INCLUDE_DIRS = ${PYTHON_INCLUDE_DIRS}") message(STATUS "Boost_LIBRARIES = ${Boost_LIBRARIES}") include_directories(${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) add_library(pylib SHARED pylib.cpp) target_link_libraries(pylib ${Boost_LIBRARIES} ${PYTHON_LIBRARIES}) # 设置库的后缀和前缀,符合Python扩展命名规范 set_target_properties(pylib PROPERTIES SUFFIX .so) set_target_properties(pylib PROPERTIES PREFIX "")
3. 清理旧编译文件并重新构建
删除之前的编译目录,避免残留旧版本的编译产物:
rm -rf cmake-build-debug mkdir cmake-build-debug && cd cmake-build-debug cmake .. -DCMAKE_BUILD_TYPE=Debug make
4. 验证版本一致性
编译完成后,在运行Python代码的环境里先确认版本:
import sys print(sys.version)
确保这个版本和CMake输出里的PYTHON_EXECUTABLE版本完全一致。
额外优化建议
建议移除C++头文件里的using namespace std;,它可能和Boost.Python的命名空间产生冲突,修改后的Bonjour.hpp如下:
#include <iostream> #include <string> class Bonjour { std::string m_msg; public: Bonjour(std::string msg):m_msg(msg) { } void greet() { std::cout << m_msg << std::endl; } void check_func() { std::cout<<"Hello! I am working"; } void set_msg(std::string msg) { this->m_msg = msg; } std::string get_msg() const { return m_msg; } };
验证修复
重新编译后,运行你的Python代码:
from pylib import Bonjour b = Bonjour("He") b.greet() # 应输出"He" print(b.msg) # 应输出"He" b.msg = "Hello World" b.greet() # 应输出"Hello World"
内容的提问来源于stack exchange,提问作者Prakhar Agarwal
相关产品推荐
相关产品推荐

