将.h文件中的常量导入python

时间:2013-03-08 12:04:12

标签: python c header constants ctypes

我一直在寻找这个问题的简单答案,但似乎找不到一个。我宁愿远离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 个答案:

答案 0 :(得分:15)

一般来说,在C头文件中定义变量的风格很差。头文件应该只声明对象,留下他们对相应“.c”源代码文件的定义。

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

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

现在,您通常使用ctypes加载Python中的目标文件,如下所示:

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

但是你会看到ctypes认为libfoo.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的值?您将其转换为const double *并取消引用它:*(const double *)(pi_view)

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

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

答案 1 :(得分:11)

我建议使用正则表达式(re模块)来解析文件中所需的信息。

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

请注意'gotcha'工件,例如注释掉的代码!

答案 2 :(得分:2)

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

答案 3 :(得分:1)

我向emilio投票,但我缺乏代表!

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

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