2013-03-08 26 views
14

Tôi đã tìm kiếm một câu trả lời đơn giản cho câu hỏi này, nhưng có vẻ như tôi không thể tìm thấy câu trả lời. Tôi muốn tránh xa bất kỳ thư viện bên ngoài nào chưa được bao gồm trong Python 2.6/2.7.Nhập hằng số từ tệp .h vào python

tôi có 2 c tập tin tiêu đề tương tự như sau:

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

...

Và tôi có một lớp python mà tôi muốn nhập khẩu các hằng số này thành:

#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 

...

tôi có mã c trong đó sử dụng các hằng số là tốt, và tương tự như này:

//computations.c 
#include <stdio.h> 
#include <math.h> 
#include "constants_a.h" 

// do some calculations, blah blah blah 

Làm thế nào tôi có thể nhập các hằng số từ tập tin header vào lớp Python?

Lý do cho tệp tiêu đề constants_a.h và constants_b.h là tôi đang sử dụng python để thực hiện hầu hết các phép tính bằng cách sử dụng hằng số, nhưng tại một thời điểm tôi cần sử dụng C để thực hiện các phép tính tối ưu hơn. Tại thời điểm này tôi đang sử dụng ctypes để bọc mã c vào Python. Tôi muốn giữ các hằng số cách xa mã chỉ trong trường hợp tôi cần phải cập nhật hoặc thay đổi chúng, và làm cho mã của tôi sạch hơn nhiều. Tôi không biết nếu nó giúp để lưu ý tôi cũng đang sử dụng NumPy, nhưng khác hơn thế, không có phần mở rộng Python không chuẩn khác. Tôi cũng mở ra bất kỳ đề xuất nào liên quan đến thiết kế hoặc kiến ​​trúc của chương trình này.

+0

Xin lỗi vì sự phản hồi muộn của mọi người. Tôi đã có một dự án mới, khẩn cấp mà tôi đang làm việc, và phải đặt nó vào thùng rác. Hiện tại, tôi đang mắc kẹt giữa câu trả lời của Công và Emilio. Tôi có lẽ sẽ dựa nhiều hơn vào việc triển khai các ctypes của Công, nhưng tôi vẫn thực sự thích phương pháp phân tích cú pháp bằng cách sử dụng 're'. Cảm ơn những ý tưởng tuyệt vời tất cả mọi người! –

Trả lời

12

Tôi khuyên bạn nên sử dụng cụm từ thông dụng (re mô-đun) để phân tích cú pháp thông tin bạn muốn ra khỏi tệp.

Xây dựng trình phân tích cú pháp C đầy đủ sẽ rất lớn, nhưng nếu bạn chỉ sử dụng các biến và tệp là đơn giản/có thể dự đoán/kiểm soát hợp lý, thì những gì bạn cần viết là đơn giản.

Chỉ xem ra các hiện vật 'gotcha' như mã nhận xét!

+3

Hãy xem tập lệnh [Tools/Scripts/h2py.py] (http://hg.python.org/cpython/log/70274d53c1dd/Tools/scripts/h2py.py), được sửa đổi từ năm 1992. – eryksun

+0

Cảm ơn Emilio và eryksun. Cho đến khi tôi nhìn thấy câu trả lời của Công, tôi tin rằng đây là con đường để đi. Nó sẽ là một bài tập tốt để viết một phân tích cú pháp nhỏ cho mục đích này. –

+0

@ManilaThrilla: Bạn rất được hoan nghênh.Tôi đã đọc và upvoted câu trả lời của Công, nó là rất nhiều thông tin. Vì một câu trả lời tốt hơn là không thể xuất hiện sau tất cả thời gian này, tôi đề nghị bạn đánh dấu của Công là được chấp nhận. –

1

Tôi muốn bỏ phiếu emilio, nhưng tôi thiếu đại diện!

Mặc dù bạn đã yêu cầu tránh các thư viện không chuẩn khác, bạn có thể xem Cython (Cython: C-Extensions cho Python www.cython.org/), cung cấp tính linh hoạt của mã hóa Python và tốc độ thực thi của mã C/C++ - được biên dịch.

Bằng cách này bạn có thể sử dụng Python thông thường cho mọi thứ, nhưng xử lý các phần tử đắt tiền của mã bằng cách sử dụng các loại C tích hợp sẵn. Sau đó bạn có thể chuyển đổi mã Python của bạn thành các tệp .c quá (hoặc chỉ cần bọc các thư viện C bên ngoài.), Sau đó có thể được biên dịch thành một tệp nhị phân. Tôi đã đạt được tới 10 lần tăng tốc làm như vậy cho các thói quen số. Tôi cũng tin rằng NumPy sử dụng nó.

+0

Tôi ban đầu đã triển khai mã của tôi trong Cython, nhưng giống như tôi đã nêu trong câu hỏi của mình, tôi đang sử dụng ctypes ngay bây giờ để duy trì tính di động. Vấn đề là Cython không có sẵn trong thư viện Python chuẩn, nhưng ctypes là. Nhưng bạn nói đúng, Cython là tuyệt vời và rất dễ sử dụng. Tôi đã tìm thấy ctypes là một vài micro giây nhanh hơn so với cython mặc dù. –

3

Tôi khuyên bạn nên sử dụng một số loại tệp cấu hình có thể đọc được bằng cả chương trình Python và C, thay vì lưu trữ giá trị không đổi trong tiêu đề. Ví dụ. một tệp csv, ini-file đơn giản hoặc thậm chí là định dạng đơn giản của các cặp 'khóa: giá trị' của riêng bạn.Và sẽ không cần phải biên dịch lại chương trình C mỗi lần bạn muốn thay đổi một trong các giá trị :)

+0

Điều này nghe có vẻ tuyệt vời, nhưng tôi nghĩ sau đó tôi sẽ phải tạo một trình phân tích cú pháp cho chương trình C mà tôi không muốn làm hoặc sử dụng thư viện như LibConfig mà tôi cũng không muốn làm. Mặc dù vậy, sẽ tốt nếu không phải biên dịch lại chương trình C mỗi lần. Bạn có thể có một ví dụ cho tập tin cấu hình này? –

+0

Cấu hình được định dạng JSON làm ví dụ. Được hỗ trợ bởi thư viện chuẩn của Python và rất nhiều triển khai cho C có sẵn trên http://www.json.org/ –

11

Nói chung, xác định các biến số trong tệp tiêu đề C là kiểu kém. Tệp tiêu đề chỉ nên khai báo các đối tượng, để lại định nghĩa của chúng cho tệp mã nguồn ".c" thích hợp. Một điều bạn có thể muốn làm là khai báo các hằng số thư viện toàn cầu như extern const whatever_type_t foo; và xác định (hoặc "thực hiện") chúng (nghĩa là gán các giá trị cho chúng) ở đâu đó trong mã C của bạn (hãy chắc chắn bạn chỉ làm điều này một lần).).

Dù sao, hãy bỏ qua cách bạn làm điều đó. Chỉ cần giả sử bạn đã xác định các hằng số và làm cho các ký hiệu của chúng hiển thị trong tệp đối tượng được chia sẻ của bạn "libfoo.so". Giả sử bạn muốn truy cập vào biểu tượng pi, được định nghĩa là extern const double pi = 3.1415926; trong libfoo, từ mã Python của bạn.

Bây giờ bạn thường tải tập tin đối tượng của bạn bằng Python sử dụng ctypes như thế này:

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

Nhưng sau đó bạn sẽ thấy ctypes nghĩ libfoo.pi là một chức năng, không phải là một biểu tượng cho dữ liệu liên tục!

>>> libfoo.pi 
<_FuncPtr object at 0x1c9c6d0> 

Để truy cập giá trị của nó, bạn phải làm một cái gì đó khá vụng về - đúc gì ctypes nghĩ là một chức năng lại thành một số.

>>> pi = ctypes.cast(foo.pi, ctypes.POINTER(ctypes.c_double)) 
>>> pi.contents.value 
3.1415926 

Trong C thuật ngữ, điều này mơ hồ tương ứng với những điều sau đây xảy ra: Bạn có một const double pi, nhưng ai đó buộc bạn phải sử dụng nó chỉ qua một con trỏ hàm:

typedef int (*view_anything_as_a_function_t)(void); 
view_anyting_as_a_function_t pi_view = &pi; 

Bạn sẽ làm gì với con trỏ pi_view để sử dụng giá trị của pi? Bạn đưa nó trở lại dưới dạng const double * và dereference nó: *(const double *)(pi_view).

Vì vậy, điều này rất khó xử. Có lẽ tôi đang thiếu một cái gì đó nhưng điều này tôi tin là do thiết kế của mô-đun ctypes - đó là chủ yếu để thực hiện cuộc gọi chức năng nước ngoài, không phải để truy cập dữ liệu "nước ngoài". Và xuất khẩu biểu tượng dữ liệu thuần túy trong một thư viện có thể tải được cho là hiếm.

Và điều này sẽ không hoạt động nếu các hằng số chỉ là các định nghĩa macro C. Nói chung không có cách nào bạn có thể truy cập dữ liệu do macro xác định bên ngoài. Chúng được mở rộng macro tại thời gian biên dịch, không để lại biểu tượng hiển thị trong tệp thư viện được tạo, trừ khi bạn cũng xuất các giá trị macro của chúng trong mã C của bạn.

+2

Vâng, tôi chỉ tìm ra cách không vụng về để làm điều này: http://python.net/crew/theller /ctypes/tutorial.html#accessing-values-exported-from-dlls Bạn có thể thử 'pi = ctypes.c_double (libfoo," pi ")' trong mã Python; điều này trả về một cá thể 'ctypes.c_double' và bạn có thể truy cập giá trị của nó bằng' pi.value'. –

+0

Cảm ơn Công vì câu trả lời rất chi tiết của bạn. Tôi nghĩ rằng việc truy cập các giá trị của các cá thể sẽ phù hợp với công việc của tôi. Đó là một nỗ lực khoa học hơn là một bản phát hành phần mềm thực sự, vì vậy tôi sẽ dễ dàng và rõ ràng. Tôi tò mò, tuy nhiên, như những gì bạn sẽ xem xét một phong cách tốt hơn để xác định hằng số. Hãy nhớ rằng các hằng số này phải nằm trong một tệp riêng biệt để nó là một vấn đề đơn giản để nhanh chóng chỉnh sửa hoặc thay đổi giá trị của chúng. –

Các vấn đề liên quan