Короткий ответ: да и нет.
Нет, нет удобной синтаксической идиомы для быстрой вставки атрибута класса в cdef class
. Однако ....
Весь смысл cython
заключается в том, что он дает вам доступ на более низкий уровень. Обычным мотивом для дополнительных усилий является производительность, но вы также можете делать C
-подобные вещи с дополнительной свободой. Трудность в том, что есть много подводных камней, и в этом случае вы не получите чистых атрибутов класса python
без большой работы. Тем не менее довольно легко получить то, что вам нужно для простых случаев использования.
Например, предположим, что я делаю калькулятор как класс, и хочу глобально установить точность возвращаемого значения для всех экземпляров. Я хочу дефолт во время компиляции, и время от времени я могу настроить его ниже, чтобы быстро обработать некоторые испытания, а затем настроить его для моей последней работы. Атрибут класса на заказ, но вы можете получить необходимую функциональность в cython
следующим образом:
Во-первых, определить на уровне модуля следующее:
cdef int _precision[1] # storage for my class 'attribute'
_precision[0]=8 # my default value, set during compilation
Использование массива позволяет использовать cython
idiom precision[0]
, что эквивалентно C *precision
. Имя cdef
precision
является неявным указателем, поскольку элемент данных представляет собой массив. Это позволяет использовать синтаксические идиомы cython
для конвертации из cython
мест хранения в ссылки на питоны. Если все, что вам нужно, это глобальная константа, к которой может обращаться код cdef
в любом из классов модуля, все готово. Если вы хотите использовать его строго как атрибут класса, вы должны обеспечить соблюдение этой дисциплины - компилятору все равно.
Теперь, если вы хотите, чтобы настроить значение от python
кода, вам потребуется пара cdef
функций, python
код в модуле может позвонить, чтобы получить доступ к атрибуту «»:
cdef int* get_precision(): return _precision
cdef void* set_precision(int i): _precision[0]=i
На данный момент , семантика будет немного отличаться от чистого python
, если вы действительно не хотите потеть. Вам нужны python
и присваиватель функция, и я считаю, протокол python
дескриптора реализован по свойствам проще:
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)))
Первый получает ссылку питона в «атрибут». Второй устанавливает «атрибут» с интегральным значением python
, находящимся под контролем. Интерфейс вызова и возврата функции cython
автоматически выполняет преобразования, которые сложнее, чем они выглядят.
Например, get_precision
возвращает C-pointer
. Если вы сделали разыменование в get_precision
, вы получили бы ошибку, пытающуюся вернуть C-int
в __get__
, как если бы это было python
. Если вместо этого вы просто опустили разыменование [0]
в __get__
, вы получили бы ошибку, пытающуюся вернуть C-pointer
, как если бы это был python int
. Как написано, автоматические преобразования корректно соответствуют типам. cython
очень тонкий в отношении такого рода вещей и может молча возвращать неверные значения, обнаруживаемые только во время выполнения. Может потребоваться некоторое экспериментирование, чтобы вывести правильное заклинание.
В документе docstring указывается, что вы не должны ожидать чистого атрибута класса python
. Если вы хотите подкласс и подклассы используют разные глобальные настройки, вам нужно немного попотеть. В python
все это делается автоматически.
Несмотря на это, есть и другие отличия. Атрибут реального класса может ссылаться на класс или экземпляр. Это свойство может ссылаться только на экземпляр. Установка атрибута реального класса в экземпляре создает экземпляр конкретной копии, оставляя атрибут класса нетронутым, но невидимым для измененного экземпляра.
Для данного прецедента это работает. Атрибут реального класса не нужен. Поскольку код cython
обычно менее абстрактен и вычисляется интенсивным, этого минимального подхода достаточно часто.
Вы также должны сделать его общедоступным для доступа к нему из python 'cdef public int bar' –
Спасибо за ответ. Я бы не подумал, что мой случай использования будет рассматриваться как добавление атрибутов во время работы. Я хочу определить доступные атрибуты класса один раз во время компиляции. – Pwnosaurus
жаль, что не обращал внимания. Я никогда не видел атрибут класса в cython. –