AttributeError:在 python 中导入自己的 C 编译函数时出现未定义符号

问题描述 投票:0回答:1

我正在尝试驯化

numba
cfunc
编译器;)

这是我的 base_model.py 文件(我的函数的来源)。

import numpy
import numba
import numba.pycc

cc = numba.pycc.CC('base_model')
cc.verbose = True
@cc.export('cumulativeMin','float64[:](float64[:])')  
def cumulativeMin(A):
    r = numpy.empty(len(A))
    t = numpy.inf
    for i in range(len(A)):
        t = numpy.minimum(t, A[i])
        r[i] = t
    return r


if __name__ == "__main__":
    cc.compile()

然后我这样做(在终端中,我运行 ubuntu):

$ python3 base_module.py 
base_model.py:3: NumbaPendingDeprecationWarning: The 'pycc' module is pending deprecation. Replacement technology is being developed.

Pending Deprecation in Numba 0.57.0. For more information please see: https://numba.readthedocs.io/en/stable/reference/deprecation.html#deprecation-of-the-numba-pycc-module
  import numba.pycc

然后我就这样做(用Python):

import numpy
import ctypes


mylib = ctypes.cdll.LoadLibrary('./base_model.cpython-310-x86_64-linux-gnu.so')
array = numpy.random.uniform(-1,0,1000)
mylib.cumulativeMin(array)

然后我收到此错误:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[1], line 7
      5 mylib = ctypes.cdll.LoadLibrary('./base_model.cpython-310-x86_64-linux-gnu.so')
      6 array = numpy.random.uniform(-1,0,1000)
----> 7 mylib.cumulativeMin(array)

File /usr/lib/python3.10/ctypes/__init__.py:387, in CDLL.__getattr__(self, name)
    385 if name.startswith('__') and name.endswith('__'):
    386     raise AttributeError(name)
--> 387 func = self.__getitem__(name)
    388 setattr(self, name, func)
    389 return func

File /usr/lib/python3.10/ctypes/__init__.py:392, in CDLL.__getitem__(self, name_or_ordinal)
    391 def __getitem__(self, name_or_ordinal):
--> 392     func = self._FuncPtr((name_or_ordinal, self))
    393     if not isinstance(name_or_ordinal, int):
    394         func.__name__ = name_or_ordinal

AttributeError: ./base_model.cpython-310-x86_64-linux-gnu.so: undefined symbol: cumulativeMin

#编辑:

我希望提前编译这个函数(cumulativeMin)(https://numba.pydata.org/numba-doc/dev/user/pycc.html)。

python ctypes numba
1个回答
1
投票

这不是您应该导入 numba/pycc 生成的代码的方式。

ctypes
用于使用外部库,不是为 python 编译的。 当然,它的构建更简单(尤其是对于 C 程序员来说。您只需像平常一样编写 C 代码,而不关心 python,并让 ctypes(在显式包装的帮助下)处理它)。您甚至可以使用任何已存在的 .so ,而不是出于该目的编写的。但也不太确定。只要给出错误的参数,你就很容易出现段错误。而且你必须自己管理C世界的内存。并且不能直接弄乱 python 数据。

这是 cpython 扩展。所以“纯Python”函数是用C 编写的,如果我可以使用这个矛盾的话。使用 python 内存管理(垃圾收集器)来创建 python 数据的函数。 更难编写,因为您必须读取和写入 python 内部数据格式(当然使用提供的 python API)。 但当然,无论如何,生成代码时都是更好的选择。

无论标准是什么,无论如何,要点是,它是一个 python 模块,应该在 python 代码中导入,可以访问 cpython api。

长话短说:

import base_model
base_model.cumulativeMin(...)

这是你应该使用它的方式。

编辑

因为我的答案是,我很确定,不明白,所以我更明确地表达它(即使这主要是通过重复问题)

我所做的是

创建

MySource.py
文件

import numpy
import numba
import numba.pycc

cc = numba.pycc.CC('base_model')
cc.verbose = True
@cc.export('cumulativeMin','float64[:](float64[:])')  
def cumulativeMin(A):
    r = numpy.empty(len(A))
    t = numpy.inf
    for i in range(len(A)):
        t = numpy.minimum(t, A[i])
        r[i] = t
    return r


if __name__ == "__main__":
    cc.compile()

然后我这样做(在终端中,我运行 ubuntu):

$ python3 MySource.py 
MySource.py:3: NumbaPendingDeprecationWarning: The 'pycc' module is pending deprecation. Replacement technology is being developed.

Pending Deprecation in Numba 0.57.0. For more information please see: https://numba.readthedocs.io/en/stable/reference/deprecation.html#deprecation-of-the-numba-pycc-module
  import numba.pycc

然后我就这样做(用Python):

import numpy
import base_model
array = numpy.random.uniform(-1,0,1000)
base_model.cumulativeMin(array)

我没有收到错误,但结果

array([-0.00492896, -0.80422352, -0.80422352, -0.80422352, -0.80422352,
       -0.80422352, -0.8844663 , -0.8844663 , -0.8844663 , -0.8844663 ,
       -0.8844663 , -0.90776422, -0.90776422, -0.90776422, -0.90776422,
...
       -0.99972223, -0.99972223, -0.99972223, -0.99972223, -0.99972223,
       -0.99972223, -0.99972223, -0.99972223, -0.99972223, -0.99972223])

请注意,除了我的主要答案之外(不要使用 ctypes 加载它,而是使用 import 加载它),我在答案中只更改了一件事:我更改了源文件的名称,从

base_model.py 
mySource.py
。 澄清一点:这里
import base_model
导入的是
.so
而不是
.py
文件。它是加载的编译文件。

© www.soinside.com 2019 - 2024. All rights reserved.