Python手册说您可以在C和C++中为Python创建模块.使用C++时,您可以利用类和模板之类的东西吗?它不会与其他库和解释器产生不兼容性吗?
我正在重新评估将外部 C 库包装到 Python 中的不同方法。我很久以前就选择使用简单的 Python C API,它快速、简单、独立,而且正如我认为的那样,它是面向未来的。然后我偶然发现了PyPy,它显然不打算支持 CPython API,但将来可能会成为一个有趣的替代方案......因此我正在寻找一个更高级别的入口点。ctypes速度很慢,所以现在我回到了cython,它似乎正在努力支持 PyPy。
我的库有许多具有相同签名的函数,因此我广泛使用 C 预处理器宏来生成 Python 模块。我认为这在 cython 中会变得更加舒适,因为我可以访问整个 Python 语言。但是,我在为函数包装器编写工厂时遇到问题:
import cython
from numpy cimport ndarray, double_t
cimport my_c_library
cdef my_c_library.data D
ctypedef double_t DTYPE_t
cdef parse_args(ndarray[DTYPE_t] P, ndarray[DTYPE_t] x, ndarray[DTYPE_t] y):
D.n = P.size
D.m = x.size
D.P = <double*> P.data
D.x = <double*> x.data
D.y = <double*> y.data
def _fun_factory(name):
cpdef fun(ndarray[DTYPE_t] P, ndarray[DTYPE_t] x, ndarray[DTYPE_t] y):
parse_args(P, x, y)
getattr(my_c_library, name)(&D) …Run Code Online (Sandbox Code Playgroud) 我最近开始使用Boost的Python库来包装一个相当大的C++库的一部分.
很偶然,我发现Boost Python创建的每个Python对象至少比Python List的大小要大.
使用noddy_NoddyType例如从C-Python的API文档,我可以很容易地露出新对象类型实例,noddy_NoddyObject.
使用原始C-Python API,这与自定义Python对象一样小而简单: -
>>> import noddy, sys
>>> print sys.getsizeof( noddy.Noddy ) # PyTypeObject size?
872
>>> print sys.getsizeof( noddy.Noddy() ) # PyObject size
16
Run Code Online (Sandbox Code Playgroud)
并与基础对象进行比较: -
>>> print sys.getsizeof( object )
872
>>> print sys.getsizeof( object() )
16
Run Code Online (Sandbox Code Playgroud)
这是预期的,但是当我noddy_NoddyObject使用Boost Python 公开时呢?
>>> print sys.getsizeof( noddy.Noddy )
904
>>> print sys.getsizeof( noddy.Noddy() )
80
Run Code Online (Sandbox Code Playgroud)
说什么?!!那不太理想......对象实例比它们需要的大5倍!
(这在非64位计算机上会有所不同.)
我几乎完全用C++编写了一个Python包.这样做的原因是因为我想手动包装现有的C++库,但这与此无关.
这个Python包由许多不同的扩展模块组成,所有这些模块都是在'setup.py'脚本中用distutils编译的.这些扩展模块可以是相互关联的,在这种情况下,我通过将共享库传递给Extension构造函数来链接它们.要清楚,假设我有两个Python C++模块,A和B,其中B使用A中定义的函数.这些通常编译成A.so和B.so. 由于B使用A中定义的函数,因此我像往常一样编译A模块,然后将':A.so'作为库传递给B模块的Extension构造函数中的libraries关键字.(':'让g ++处理这个事实,即库不以通常的'lib'前缀开头.)这适用于链接函数和类.
我的问题如下:我在A中定义了一些全局C++变量.虽然我所描述的内容允许B访问A中的函数,但它实际上似乎创建了A中定义的任何全局数据的COPY.这是一个真正的问题为了我.
在我看来,该问题基本上类似于在共享库中具有全局变量,如此处和其他地方所讨论的.该解决方案以及我在网上找到的其他解决方案似乎无法解决问题.
任何帮助将非常感谢!
编辑:忘记提及,是的,我的全局变量被声明为extern.
我很难让我的测试框架适用于Python2和Python3的C扩展模块.我喜欢运行我的文档字符串doctest以确保我没有向用户提供不良信息,所以我想在doctest测试中运行.
我不相信我的问题的根源是文档字符串本身,而是doctest模块如何尝试读取我的扩展模块.如果我运行doctestPython2(在针对Python2编译的模块上),我得到了我期望的输出:
$ python -m doctest myext.so -v
...
1 items passed all tests:
98 tests in myext.so
98 tests in 1 items.
98 passed and 0 failed.
Test passed.
Run Code Online (Sandbox Code Playgroud)
但是,当我使用Python3时,我得到了一个UnicodeDecodeError:
$ python3 -m doctest myext3.so -v
Traceback (most recent call last):
...
File "/usr/local/Cellar/python3/3.3.3/Frameworks/Python.framework/Versions/3.3/lib/python3.3/doctest.py", line 223, in _load_testfile
return f.read(), filename
File "/usr/local/Cellar/python3/3.3.3/Frameworks/Python.framework/Versions/3.3/lib/python3.3/codecs.py", line 301, in decode
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte …Run Code Online (Sandbox Code Playgroud) 我有一个 C 扩展,它实现了 LRU 缓存https://github.com/pbrady/fastcache。我最近注意到,在一个大量使用缓存的应用程序(SymPy)中,超时信号丢失,而应用程序继续运行。仅当使用我的 C 扩展而不是使用纯 Python LRU 缓存(即 functools.lru_cache)时才会发生这种情况https://github.com/pbrady/fastcache/issues/26。
我在例程中添加了对 PyErr_CheckSignals() 的调用,信号丢失的频率降低了,但这种情况仍然会发生。请注意,在调用期间,缓存将调用 PyObject_Hash、PyDict_Get/Set/DelItem 和 PyObject_Call(在未命中的情况下)。
这是 SymPy 代码的相关片段(超时是一个整数):
def _timeout(self, function, timeout):
def callback(x, y):
signal.alarm(0)
raise Skipped("Timeout")
signal.signal(signal.SIGALRM, callback)
signal.alarm(timeout) # Set an alarm with a given timeout
function()
signal.alarm(0) # Disable the alarm enter code here
Run Code Online (Sandbox Code Playgroud)
有什么东西会覆盖信号吗?如果是这样,我该如何解决这个问题?
我正在开发一个大型 Python 项目,其中包含多个 C/C++ 扩展。目前,每次我想让代码在新机器上运行时,我都必须从存储库下载所有内容,然后运行python setup.py install几次,每个扩展一次......并且假设计算机安装了 C 编译器 - 如果事实并非如此,这还需要一两个额外的步骤。
有什么方法可以预编译所有 C 扩展,以便当我将存储库下载到新机器时,一切都可以开箱即用,而无需单独安装所有这些子组件?我知道这在不同平台上可能无法正常工作(或根本无法工作?),但假设我在 64 位 Windows 8 计算机上预编译了一些内容,并想将其安装在另一台 64 位 Windows 8 计算机上 - 是那可能吗?如果是这样,我将如何去做呢?
我需要使用 distutils (和/或 setuptools)创建一个 C 扩展,它可以在运行时和编译时动态使用(用于不同的目的)。这在 Linux 上不是问题,但在 OS X 上却是问题。默认情况下,distutils 在 OS X 上创建一个“捆绑包”(并将其命名为 .so),它可以在运行时使用,但不能在编译时使用。我需要制作一个 .dylib,它可以在编译时链接到,并且我需要在可以为 PyPI 打包的 setup.py 中执行此操作。
无论我尝试什么,distutils 都会不断创建捆绑包,当我尝试链接该库时,我收到错误。您可以通过在命令行上使用 file 显式检查 distutils 是否创建了捆绑包或动态链接库:
file libA.so
libA.so: Mach-O 64-bit bundle x86_64
Run Code Online (Sandbox Code Playgroud)
以下 cc 命令给了我我想要的:
cc -fPIC -shared source1.o source2.o -o libA.so
file libA.so
libA.so: Mach-O 64-bit dynamically linked shared library x86_64
Run Code Online (Sandbox Code Playgroud) macos distutils shared-libraries setuptools python-c-extension
让我们说我想gcc从命令行使用,以编译Python的C扩展.我将这样的调用结构如下:
gcc -o applesauce.pyd -I C:/Python35/include -L C:/Python35/libs -l python35 applesauce.c
Run Code Online (Sandbox Code Playgroud)
我注意到-I,-L和-l选项是绝对必要的,否则你会得到类似如下的错误此.这些命令告诉gcc在哪里查找headers(-I),在哪里查找静态库(-L),以及实际使用哪个静态库(python35实际转换为libpython35.a).
现在,显然很容易获得libs和include你的机器一样的目录,因为如果你不想让它们永远不会改变.但是,我正在编写一个gcc从命令行调用的程序,其他人将使用该程序.发生此调用的行看起来像这样:
from subprocess import call
import sys
filename = applesauce.c
include_directory = os.path.join(sys.exec_prefix, 'include')
libs_directory = os.path.join(sys.exec_prefix, 'libs')
call(['gcc', ..., '-I', include_direcory, '-L', libs_directory, ...])
Run Code Online (Sandbox Code Playgroud)
相反,我需要Python中的一个解决方案,它将可靠地返回include和libs目录.
我查看了该模块distutils.ccompiler,发现了许多有用的函数,它们部分地使用了distutils,但是让我可以自定义我的编译器完全跨平台.唯一的问题是,我需要传递包含和运行时库...
我看了一下distutils.sysconfig,我能够可靠地返回包含所有头文件的'include'目录.我仍然不知道如何获取运行时库.
该 …
Python的inspect模块似乎无法检查"内置"函数的签名,其中包括C扩展模块中定义的函数,如Cython定义的函数.有没有办法获得你在这样一个模块中定义的Python函数的签名,特别是在Cython中?我希望能够找到可用的关键字参数.
MWE:
# mwe.pyx
def example(a, b=None):
pass
Run Code Online (Sandbox Code Playgroud)
和
import pyximport; pyximport.install()
import mwe
import inspect
inspect.signature(mwe.example)
Run Code Online (Sandbox Code Playgroud)
收益率:
Traceback (most recent call last):
File "mwe_py.py", line 5, in <module>
inspect.signature(mwe.example)
File "/nix/store/134l79vxb91w8mhxxkj6kb5llf7dmwpm-python3-3.4.5/lib/python3.4/inspect.py", line 2063, in signature
return _signature_internal(obj)
File "/nix/store/134l79vxb91w8mhxxkj6kb5llf7dmwpm-python3-3.4.5/lib/python3.4/inspect.py", line 1965, in _signature_internal
skip_bound_arg=skip_bound_arg)
File "/nix/store/134l79vxb91w8mhxxkj6kb5llf7dmwpm-python3-3.4.5/lib/python3.4/inspect.py", line 1890, in _signature_from_builtin
raise ValueError("no signature found for builtin {!r}".format(func))
ValueError: no signature found for builtin <built-in function example>
Run Code Online (Sandbox Code Playgroud)
在Python 3.4.5和Cython 0.24.1中
python ×9
c ×3
c++ ×3
cython ×2
numpy ×2
python-c-api ×2
boost-python ×1
distutils ×1
doctest ×1
gcc ×1
macos ×1
python-3.x ×1
setuptools ×1
signals ×1