python - 这是 Boost::Python (Python 3.7) 错误 "__init__() should return None, not ' NoneType'"链接问题吗?

标签 python c++ python-3.x boost boost-python

更新

我不会添加这个作为答案,因为我还没有从技术上解决问题。但是自从我现在花了 2.5 天时间尝试让 boost-python3 正常工作后,我就失去了使用它的意愿。

我刚刚遇到 pybind11 (我之前对 python 绑定(bind)工具的冗长搜索是如何没有出现的,我不知道)并且正在使用它。 2.5 天的痛苦与 <20 分钟的安装和构建 cmake example 相比...并且所有特定的 python 版本依赖性 hell 都消失了。

它在语法上类似于 boost-python,但更易于管理、更快、仅包含 header 且功能更丰富。

耶!

原始问题

我正在使用 boost::python 绑定(bind) python 3.7.2 中的类。

类导入成功但实例化出现如下错误:

<my-terminal>$ python
Python 3.7.2 (default, Feb 14 2019, 17:36:47) 
[Clang 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import classes
>>> t = classes.World()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() should return None, not 'NoneType'
>>> 

这是classes.cpp:

#include <boost/python.hpp>
#include <boost/python/list.hpp>
#include <boost/python/extract.hpp>
#include <string>
#include <sstream>
#include <vector>

struct World
{
    void set(std::string msg) { mMsg = msg; }
    void many(boost::python::list msgs) {
        long l = len(msgs);
        std::stringstream ss;
        for (long i = 0; i<l; ++i) {
            if (i>0) ss << ", ";
            std::string s = boost::python::extract<std::string>(msgs[i]);
            ss << s;
        }
        mMsg = ss.str();
    }
    std::string greet() { return mMsg; }
    std::string mMsg;
};

using namespace boost::python;

BOOST_PYTHON_MODULE(classes)
{
    class_<World>("World")
        .def("greet", &World::greet)
        .def("set", &World::set)
        .def("many", &World::many)
    ;
};

假设

This question, almost identical由于 python 2/3 问题(链接到 python 3 而不是 python 2 库)而被解决。所以我怀疑是库链接问题。

验证假设

我无法让 bjam 工作,并且无论如何也无法为一个模块切换我们所有的构建系统......所以我正在使用 cmake 进行构建,它成功编译为 classes.so 输出如下,表明我找到了所有正确的包含、库和可执行文件:

-- Found PythonInterp: /Users/me/.pyenv/versions/boost37/bin/python3 (found suitable version "3.7.2", minimum required is "3") 
PYTHON_VERSION_SUFFIX
-- Boost version: 1.68.0
-- Found the following Boost libraries:
--   python37
-- Found PythonLibs: /usr/local/Frameworks/Python.framework/Versions/3.7/lib/libpython3.7m.dylib (found suitable version "3.7.2", minimum required is "3") 
-- PYTHON_LIBRARIES = /usr/local/Frameworks/Python.framework/Versions/3.7/lib/libpython3.7m.dylib
-- PYTHON_EXECUTABLE = /Users/thc29/.pyenv/versions/boost37/bin/python3
-- PYTHON_INCLUDE_DIRS = /usr/local/Frameworks/Python.framework/Versions/3.7/include/python3.7m
-- Boost_LIBRARIES = /usr/local/lib/libboost_python37-mt.dylib

Boost-python3库目录内容:

ls /usr/local/Cellar/boost-python3/1.68.0/lib
libboost_numpy37-mt.a       libboost_numpy37.dylib      libboost_python37.a
libboost_numpy37-mt.dylib   libboost_python37-mt.a      libboost_python37.dylib
libboost_numpy37.a      libboost_python37-mt.dylib

我使用 brew install boostbrew install boost-python3 --build-from-source 激活了我的 python 3.7 virtualenv,以确保 boost-python3 已链接针对正确版本的 python。

正在检查库...

otool -L classes.so 给出:

classes.so:
    /usr/l/opt/boost-python3/lib/libboost_python37-mt.dylib (compatibility version 0.0.0, current version 0.0.0)
    /usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/Python (compatibility version 3.7.0, current version 3.7.0)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)

otool -L/usr/local/opt/boost-python3/lib/libboost_python37-mt.dylib 给出:

/usr/local/opt/boost-python3/lib/libboost_python37-mt.dylib:
        /usr/local/opt/boost-python3/lib/libboost_python37-mt.dylib (compatibility version 0.0.0, current version 0.0.0)
        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)

在相关问题中,这表明了他们的问题。但这里看起来很好!

还没有进展...

在正确编译并检查链接的痛苦过程之后,我无法发现任何缺陷。这是一个不同的问题吗?还是存在我没有发现的链接问题?

感谢您的帮助!

最佳答案

在此处为使用 Anaconda 或 Conda-Forge Distribution 的用户添加答案:

python 解释器静态链接在 libpythonXY 库中。这就是为什么它使 python 二进制文件与其他发行版不同。

OP 报告的问题的修复方法是使用:

-undefined dynamic_lookup

代替:

-lpythonXY

您正在创建 Python C/C++ 扩展,而不是嵌入 Python 解释器。所以你不应该链接到 python 库。 Pybind11 正确处理了这个问题。

有关详细信息,请参阅以下内容:

附带说明一下,python 3.8 添加了一个额外的标志:--embed 并且只有这样它才会在输出中添加 -lpythonXY:

$ python3.8-config --libs
-ldl -framework CoreFoundation

$ python3.8-config --libs --embed
-lpython3.8 -ldl -framework CoreFoundation

关于python - 这是 Boost::Python (Python 3.7) 错误 "__init__() should return None, not ' NoneType'"链接问题吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54708598/

相关文章:

c++ - Boost函数指针多线程之谜

c++ - 如何为一段代码启用 -fpermissive

python - 解析 Python 类中的菱形继承(钻石问题)

python - 在 for 循环中构建不同的 networkx 图

python多处理池,让一个 worker 执行不同的功能

Android 应用程序因 C++ 中的字符串操作而崩溃

python-3.x - 在移动摄像机中检测移动物体(监视安装在无人机上的一个区域)

python - 使用触摸屏启动时运行 Python 脚本时显示名称错误

python - 调用以某物开头的类的所有方法

python - 如何防止堆栈对索引进行排序?