这是Boost :: Python(Python 3.7)错误“ __init __()应该返回None,而不是'NoneType'”链接问题吗?

时间:2019-02-15 11:41:45

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

更新

由于我在技术上还没有解决问题,因此我不会将其添加为答案。但是,由于我现在花了2.5天的时间来尝试使boost-python3正常运行,所以我失去了使用它的意愿。

我刚遇到pybind11(我不知道我以前冗长的搜索python绑定工具的过程是怎么发现的),并且正在使用它。经历了2.5天的痛苦之后,安装和构建cmake example的时间不到20分钟……而所有特定的python-version-dependency-hell都消失了。

从语法上讲,它与boost-python类似,但更易于管理,更快,仅标头且功能更丰富。

是的!

原始问题

我正在使用boost :: python绑定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进行构建,该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)

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

尚无进展...

经过痛苦的过程,正确地进行了所有编译并检查了链接,我看不到任何缺陷。这是一个不同的问题吗?还是有我没有发现的链接问题?

感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:2)

我正在跟踪similar example,并且采用here中的Makefile。我已经通过python 3.7.4上的boost-python安装了brewmacOS。要解决NoneType问题,请按照以下步骤操作:

1。检查Python路径
要检查python路径,请使用

which python

如果输出看起来不像以下内容(brew的{​​{1}}安装路径)

python

/usr/local/opt/python/libexec/bin/python 变量设置为

PATH

再次检查export PATH="/usr/local/opt/python/libexec/bin:$PATH" 路径是否类似于上面的路径。

2。检查编译标志
以下是采用的Python。请注意Makefile变量。如果LIB标志为boost-python,请将其更改为-lboost_python

-lboost_python37

重新编译CPP = clang++ PYLIBPATH = $(shell python-config --exec-prefix)/lib # LIB = -L$(PYLIBPATH) $(shell python-config --libs) -lboost_python LIB = -L$(PYLIBPATH) $(shell python-config --libs) -lboost_python37 OPTS = $(shell python-config --include) -O2 default: hello.so hello.so: hello.o $(CPP) $(LIB) -Wl,-rpath,$(PYLIBPATH) -shared $< -o $@ hello.o: hello.cpp Makefile $(CPP) $(OPTS) -c $< -o $@ clean: rm -rf *.so *.o .PHONY: default clean 代码并运行C++脚本。 python问题应该消失。

希望这会有所帮助。

注意
如果您使用的是NoneType,并想在上述更改后恢复anaconda变量,请尝试

PATH

您的export PATH="~/anaconda3/bin:$PATH" 的路径可能不同。

信用
1.在How do I use brew installed Python as the default Python?
中的 George 的评论 2. leiyc ld: library not found for -lboost_python on MacOS

中的评论