我一直在寻找这个问题的简单答案,但似乎找不到一个。我宁愿远离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扩展。我也对该计划的设计或架构提出任何建议。
答案 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_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会使用它。