Импортировать константы из.H-файл в Python

Я искал простой ответ на этот вопрос, но, похоже, я не могу его найти. Я бы предпочел держаться подальше от каких-либо внешних библиотек, которые еще не включены в 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 ответов


Я рекомендую использовать регулярные выражения (re module) для анализа информации, которую вы хотите из файлов.

создание полного синтаксического анализатора C было бы огромным, но если вы используете только переменные, а файл достаточно прост/предсказуем/под контролем, то то, что вам нужно написать, просто.

просто следите за артефактами "gotcha", такими как прокомментированный код!


в общем, определение переменные в заголовочном файле C-плохой стиль. Файл заголовка должен только объявить объекты, оставляя их определение для соответствующего ".файл с" исходным кодом.

одна вещь, которую вы можете сделать, это объявить глобальные константы библиотеки, такие как extern const whatever_type_t foo; и определить (или" реализовать") их (т. е. присвоить им значения) где-то в вашем коде C (убедитесь, что вы делаете это только один раз).

в любом случае, давайте игнорировать как сделай это. Просто предположим, что вы уже определили константы и сделали их символы видимыми в вашем общем объектном файле "libfoo.Итак". Предположим, вы хотите получить доступ к символу pi, определен как extern const double pi = 3.1415926; в libfoo, из вашего кода Python.

теперь вы обычно загружаете свой объектный файл в Python, используя ctypes такой:

>>> 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.


Я бы рекомендовал использовать какой-то файл конфигурации, читаемый как Python, так и программой C, а не хранить постоянные значения в заголовках. Е. Г. простой CSV, ini-файл, или даже ваш собственный простой формат из пар ключ-значение'. И нет необходимости перекомпилировать программу с каждый раз, когда вы хотите изменить одно из значений :)


Я бы проголосовал за Эмилио, но мне не хватает репутации!

хотя вы просили избегать других нестандартных библиотек, вы можете взглянуть на Cython (Cython: C-Extensions для Python www.cython.org/), который предлагает гибкость кодирования Python и необработанную скорость выполнения C/C++-скомпилированного кода.

таким образом, вы можете использовать обычный Python для всего, но обрабатывать дорогие элементы кода, используя его встроенные C-типы. Затем вы можете конвертировать Python код в .c-файлы тоже (или просто оберните внешние C-библиотеки сами. ), который затем может быть скомпилирован в двоичный файл. Я достиг до 10x ускорений, делая это для численных процедур. Я также считаю, что NumPy использует его.