16

我一直在寻找这个问题的简单答案,但似乎找不到。我宁愿远离 Python 2.6/2.7 中尚未包含的任何外部库。

我有 2 个类似于以下内容的 c 头文件:

//constants_a.h
const double constant1 = 2.25;
const double constant2 = -0.173;
const int constant3 = 13;

...

//constants_b.h
const double constant1 = 123.25;
const double constant2 = -0.12373;
const int constant3 = 14;

...

我有一个 python 类,我想将这些常量导入:

#pythonclass.py
class MyObject(object):
    def __init(self, mode):
        if mode is "a":
            # import from constants_a.h, like:
            # self.constant1 = constant1
            # self.constant2 = constant2
        elif mode is "b":
            # import from constants_b.h, like:
            # self.constant1 = constant1
            # self.constant2 = constant2

...

我也有使用常量的 c 代码,类似于:

//computations.c
#include <stdio.h>
#include <math.h>
#include "constants_a.h"

// do some calculations, blah blah blah

如何将头文件中的常量导入 Python 类?

头文件 constants_a.h 和 constants_b.h 的原因是我使用 python 来使用常量进行大部分计算,但有一次我需要使用 C 来进行更优化的计算。此时我正在使用 ctypes 将 c 代码包装到 Python 中。我想让常量远离代码,以防万一我需要更新或更改它们,并使我的代码更加简洁。我不知道是否有助于注意我也在使用 NumPy,但除此之外,没有其他非标准 Python 扩展。我也愿意接受有关该程序的设计或架构的任何建议。

4

4 回答 4

16

通常,在 C 头文件中定义变量的风格很差。头文件应该只声明对象,将它们的定义留给适当的“.c”源代码文件。

您可能想要做的一件事是extern const whatever_type_t foo;在 C 代码中的某处声明库全局常量并定义(或“实现”)它们(即为它们分配值)(确保只执行一次)。

无论如何,让我们忽略你是如何做到的。假设您已经定义了常量并让它们的符号在您的共享对象文件“libfoo.so”中可见。让我们假设您想从 Python 代码中访问在 libfoo 中pi定义的符号 。extern const double pi = 3.1415926;

现在,您通常使用以下方式在 Python 中加载您的目标文件ctypes

>>> import ctypes
>>> libfoo = ctypes.CDLL("path/to/libfoo.so")

但是你会看到ctypesthinkslibfoo.pi是一个函数,而不是常量数据的符号!

>>> libfoo.pi
<_FuncPtr object at 0x1c9c6d0>

要访问它的值,您必须做一些相当尴尬的事情——将ctypes认为是一个函数的内容转换一个数字。

>>> pi = ctypes.cast(foo.pi, ctypes.POINTER(ctypes.c_double))
>>> pi.contents.value
3.1415926

在 C 行话中,这模糊地对应于正在发生的以下事情:您有一个const double pi,但有人强迫您仅通过函数指针使用它:

typedef int (*view_anything_as_a_function_t)(void);
view_anyting_as_a_function_t pi_view = &pi;

pi_view为了使用 的值,您如何处理指针pi?您将其作为 a 回退const double *并取消引用它:*(const double *)(pi_view).

所以这一切都很尴尬。也许我遗漏了一些东西,但我相信这是ctypes模块的设计——它主要用于进行外部函数调用,而不是用于访问“外部”数据。在可加载库中导出纯数据符号可以说是很少见的。

如果常量只是 C 宏定义,这将不起作用。通常,您无法从外部访问宏定义的数据。它们在编译时进行宏扩展,在生成的库文件中没有可见符号,除非您还在 C 代码中导出它们的宏值。

于 2013-03-19T15:47:37.330 回答
12

我建议使用正则表达式(re模块)从文件中解析出你想要的信息。

构建一个完整的 C 解析器将是巨大的,但如果您只使用变量并且文件相当简单/可预测/受控制,那么您需要编写的内容很简单。

只需注意“陷阱”工件,例如注释掉的代码!

于 2013-03-08T12:11:01.173 回答
2

我建议使用 Python 和 C 程序都可读的某种配置文件,而不是在标头中存储常量值。例如,一个简单的 csv、ini 文件,甚至是您自己的“键:值”对的简单格式。并且每次您想更改其中一个值时都无需重新编译 C 程序 :)

于 2013-03-08T12:35:52.127 回答
1

我会投票给emilio,但我缺乏代表!

尽管您已要求避免使用其他非标准库,但您不妨看看 Cython(Cython:C-Extensions for Python www.cython.org/),它提供了 Python 编码的灵活性和原始的执行速度C/C++ 编译的代码。

通过这种方式,您可以使用常规 Python 处理所有内容,但使用其内置的 C 类型处理昂贵的代码元素。然后,您也可以将您的 Python 代码转换为 .c 文件(或者只是自己包装外部 C 库。),然后可以将其编译为二进制文件。对于数值例程,我已经实现了高达 10 倍的加速。我也相信 NumPy 使用它。

于 2013-03-08T12:25:06.727 回答