Импорт констант из файла .h в python - программирование
Подтвердить что ты не робот

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

4b9b3361

Ответ 1

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

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

Просто следите за артефактами "getcha", такими как код с комментариями!

Ответ 2

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

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

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

Теперь вы обычно загружаете свой объектный файл в Python с помощью ctypes следующим образом:

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

Но тогда вы увидите ctypes thinks 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.

Ответ 3

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

Ответ 4

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

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

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