2013-03-08 3 views
14

Я искал простой ответ на этот вопрос, но кажется, что я не могу его найти. Я предпочел бы держаться подальше от любых внешних библиотек, которые еще не включены в Python 2.6/2.7.Импорт констант из файла .h в python

У меня есть 2 заголовочные файлы, которые будут выглядеть следующим образом:

//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; 

...

И у меня есть класс питона, который я хочу импортировать эти константы указаны в:

#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 

...

У меня есть с кодом, который использует константы, а также, и это напоминает:

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

Извините за такой поздний отзыв всем. У меня был новый, срочный проект, над которым я работал, и мне пришлось наложить это на backburner. На данный момент я застрял между ответами Конга и Эмилио. Я, вероятно, больше склоняюсь к реализации ctypes в Cong, но мне по-прежнему нравится метод parsing с использованием 're'. Спасибо за отличные идеи всем! –

ответ

12

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

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

Просто следите за артефактами «gotcha», такими как код с комментариями!

+3

Посмотрите на скрипт [Tools/Scripts/h2py.py] (http://hg.python.org/cpython/log/70274d53c1dd/Tools/scripts/h2py.py), пересмотренный с 1992 года. – eryksun

+0

Спасибо Emilio и eryksun. Пока я не увидел ответ Конга, я верил, что это путь. Для этой цели было бы хорошим упражнением написать небольшой парсер. –

+0

@ ManilaThrilla: Добро пожаловать.Я прочитал и подтвердил ответ Конга, он очень информативен. Поскольку лучший ответ вряд ли появится после всего этого времени, я предлагаю вам отметить, что Конг принят. –

1

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

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

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

+0

Ну, я изначально реализовал свой код в Cython, но, как я уже сказал в своем вопросе, я использую ctypes для поддержания переносимости. Проблема в том, что Cython недоступен в стандартной библиотеке Python, но ctypes. Но вы правы, Cython потрясающий и очень прост в использовании. Я обнаружил, что ctypes будет на несколько микросекунд быстрее, чем cython. –

3

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

+0

Это звучит здорово, но я думаю, что тогда мне придется либо создать парсер для программы C, который я не хочу делать, либо использовать библиотеку LibConfig, которую я тоже не хочу делать. Было бы неплохо, однако, не перекомпилировать программу C каждый раз. Возможно, у вас есть пример для этого файла конфигурации? –

+0

Конфигурация в формате JSON в качестве примера. Поддерживается стандартной библиотекой Python и множеством реализаций для C доступны на http://www.json.org/ –

11

В целом, , определяющий переменные в файле заголовка 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") 

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

+2

Ну, я только что обнаружил неловкий способ сделать это: http://python.net/crew/theller /ctypes/tutorial.html#accessing-values-exported-from-dlls Вы можете попробовать 'pi = ctypes.c_double (libfoo," pi ")' в коде Python; это возвращает экземпляр 'ctypes.c_double', и вы можете получить доступ к его значению с помощью' pi.value'. –

+0

Спасибо, Конг за подробный ответ. Я думаю, что доступ к значениям экземпляров был бы подходящим для моей работы. Это научная работа, а не фактический выпуск программного обеспечения, поэтому я собираюсь сделать это легко и понятно. Мне любопытно, однако, что вы считаете лучшим стилем для определения констант. Имейте в виду, что эти константы должны быть в отдельном файле, так что просто быстро изменить или изменить их значения. –

Смежные вопросы