2015-02-26 16 views
9

lớp Python có thể có lớp thuộc tính:Các loại mở rộng của Cython có hỗ trợ các thuộc tính lớp không?

class Foo(object): 
    bar = 4 

Có một cấu trúc tương tự để xác định thuộc tính lớp trong các loại phần mở rộng Cython? Ví dụ, khi tôi cố gắng biên dịch đoạn mã sau cython

cdef class Foo: 
    cdef int bar 
    bar = 4 

tôi nhận được lỗi này:

thing.c:773:3: error: use of undeclared identifier 'bar' 
    bar = 4; 
^
1 error generated. 
error: command 'cc' failed with exit status 1 
+1

Bạn cũng cần đặt công khai để truy cập từ python 'cdef public int bar' –

+0

Cảm ơn bạn đã trả lời. Tôi sẽ không nghĩ rằng trường hợp sử dụng của tôi sẽ được coi là thêm thuộc tính tại thời gian chạy nghĩ. Tôi muốn xác định các thuộc tính lớp có sẵn một lần tại thời gian biên dịch. – Pwnosaurus

+0

xin lỗi có, đã không chú ý. Tôi chưa bao giờ thấy một thuộc tính lớp trong cython. –

Trả lời

1

Câu trả lời ngắn gọn là có và không.

Không, không có thành ngữ cú pháp thuận tiện để chèn nhanh thuộc tính lớp trong một cdef class. Tuy nhiên ....

Toàn bộ điểm của cython là nó mang lại cho bạn quyền truy cập cấp thấp hơn. Động cơ thông thường cho nỗ lực thêm là hiệu suất, nhưng bạn cũng có thể làm C giống như những thứ có thêm tự do. Khó khăn là, có rất nhiều cạm bẫy, và trong trường hợp này, bạn sẽ không nhận được thuộc tính lớp tinh khiết python mà không có nhiều công việc. Tuy nhiên, khá dễ dàng để có được những gì bạn cần cho các trường hợp sử dụng đơn giản.

Ví dụ: giả sử tôi đang tạo một số công cụ tính toán làm lớp và tôi muốn đặt toàn bộ độ chính xác của giá trị trả lại cho tất cả các phiên bản. Tôi muốn một mặc định tại thời gian biên dịch, và theo thời gian tôi có thể muốn điều chỉnh nó thấp hơn để nhanh chóng xử lý một số thử nghiệm, và sau đó điều chỉnh nó cao hơn cho công việc cuối cùng của tôi. Một thuộc tính lớp được thực hiện để đặt hàng, nhưng bạn có thể nhận được các chức năng mà bạn cần trong cython như sau:

Thứ nhất, xác định ở cấp mô-đun sau:

cdef int _precision[1] # storage for my class 'attribute' 
_precision[0]=8   # my default value, set during compilation 

Sử dụng một mảng cho phép chúng ta sử dụng cython thành ngữ precision[0] tương đương với C *precision. Tên cdefprecision hoàn toàn là con trỏ vì mục dữ liệu là một mảng. Điều này cho phép sử dụng cython thành ngữ cú pháp để chuyển đổi từ cython vị trí lưu trữ thành tham chiếu python. Nếu tất cả những gì bạn muốn là một hằng số toàn cầu có thể được truy cập bởi cdef mã trong bất kỳ lớp nào trong mô-đun, bạn đã hoàn tất. Nếu bạn muốn sử dụng nó đúng như một thuộc tính lớp, bạn phải thực thi kỷ luật đó - trình biên dịch không quan tâm.

Bây giờ nếu bạn cũng muốn điều chỉnh giá trị từ python mã, bạn sẽ cần một cặp cdef chức năng mà python mã trong các mô-đun có thể gọi để truy cập 'thuộc tính':

cdef int* get_precision(): return _precision 
cdef void* set_precision(int i): _precision[0]=i 

Tại thời điểm này , ngữ nghĩa sẽ thay đổi một chút từ tinh khiết python, trừ khi bạn thực sự muốn đổ mồ hôi. Bạn cần một hàm python setter và getter, và tôi tìm thấy những giao thức python mô tả được thực hiện bởi các thuộc tính là dễ nhất:

cdef class SomeCalculator: 
    ... 

    property precision: 
    def __get__(self): 
     """Get or set calculation precision, default == 8. 
     This is like a class attribute: setting affects all instances, 
     however, it also affects all subclasses.""" 
     return get_precision()[0] 
    def __set__(self,int integer): set_precision(min(30,max(0,integer))) 

Đầu tiên nhận được một tài liệu tham khảo python cho 'thuộc tính'. Cái thứ hai đặt 'thuộc tính' với giá trị tích phân python, được điều chỉnh để nằm trong giới hạn. Giao diện trả về và gọi hàm cython tự động xử lý các chuyển đổi phức tạp hơn so với giao diện của chúng.

Ví dụ: get_precision trả về số C-pointer. Nếu bạn đã thực hiện cuộc hội thảo tại get_precision, bạn sẽ gặp lỗi khi cố gắng trả lại C-int trong __get__ như thể nó là python. Thay vào đó, nếu bạn chỉ bỏ qua yêu cầu [0] trong __get__, bạn sẽ gặp lỗi khi cố gắng trả lại C-pointer như thể đó là python int. Như được viết, chuyển đổi tự động đối sánh chính xác các loại. cython là rất khó tính về loại điều này, và âm thầm có thể trả về giá trị không chính xác, chỉ có thể phát hiện khi chạy. Có thể mất một số thử nghiệm để suy ra câu thần chú chính xác.

Chuỗi tài liệu yêu cầu bạn không mong đợi thuộc tính lớp thuần túy python. Nếu bạn muốn sub-class, và có các lớp con sử dụng một thiết lập toàn cầu khác, bạn sẽ cần phải đổ mồ hôi nhiều hơn một chút. Trong python, tất cả được thực hiện tự động.

Mặc dù vậy, có những khác biệt khác. Một thuộc tính lớp thực có thể được tham chiếu trên lớp hoặc trên một cá thể. Thuộc tính này chỉ có thể được tham chiếu trên một cá thể. Việc thiết lập thuộc tính lớp thực trên cá thể tạo ra một bản sao cá thể cụ thể, để lại thuộc tính lớp bị ảnh hưởng, nhưng ẩn với cá thể đã thay đổi.

Đối với trường hợp sử dụng đã cho, tính năng này hoạt động. Một thuộc tính lớp thực là không cần thiết. Vì mã cython thường ít trừu tượng và tính toán chuyên sâu, cách tiếp cận tối thiểu này thường đủ.

1

Bạn không thể làm điều đó theo cách đó. Tôi không biết liệu các thuộc tính tĩnh có được hỗ trợ hay không, nhưng các thuộc tính "bình thường" phải được truy cập từ các phương thức, ví dụ: một constructor:

cdef class Foo: 
    cdef int bar 
    def __init__(self): 
     self.bar = 4 
5

Trong khi nó dường như không thể để có các thuộc tính tĩnh C-gõ, các loại phần mở rộng Cython thể có Python thuộc tính thường xuyên tĩnh mà cũng sẽ được tự động truy cập bằng Python. Chỉ cần khai báo chúng như bạn sẽ khai báo bằng Python:

cdef class Foo: 
    bar = 4 

Các mã được tạo cho thấy rằng những thuộc tính tĩnh được lưu trữ như các đối tượng Python trong dict thuộc tính của đối tượng lớp, tức là nếu bạn sử dụng chúng trong bối cảnh nơi C- loại được sử dụng, chúng được chuyển đổi trở lại từ các đối tượng Python.

+1

Trong thực tế, tôi nghi ngờ không có gì giống như một thuộc tính lớp tĩnh có thể trong cpython * ngoại trừ * như là một phần tử của nó '__dict__'; so sánh: 'type (" MyType ", (type,), {'__slots __' :('foo',)})' – SingleNegationElimination

+1

dường như đây là chỉ đọc. Có cách nào để tạo các thuộc tính lớp trong một phần mở rộng của Cython có thể truy cập công khai không? – Zephyr

+0

xác định getter và setter cho chúng –

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