Les types d’extension Cython prennent-ils en charge les atsortingbuts de classe?

Les classes Python peuvent avoir des atsortingbuts de classe:

class Foo(object): bar = 4 

Existe-t-il une construction analogue pour définir les atsortingbuts de classe dans les types d’extension Cython? Par exemple, lorsque je tente de comstackr le code cython suivant

 cdef class Foo: cdef int bar bar = 4 

Je reçois cette erreur:

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

La réponse courte est oui et non.

Non, il n’y a pas d’idiome syntaxique commode pour insérer rapidement un atsortingbut de classe dans une cdef class . Toutefois ….

Le but de cython est qu’il vous donne un access de niveau inférieur. Le motif habituel de l’effort supplémentaire est la performance, mais vous pouvez également faire des choses semblables à celles du C avec une liberté supplémentaire. La difficulté est qu’il existe de nombreux pièges et que, dans ce cas, vous n’obtiendrez pas d’atsortingbuts de classe python purs sans beaucoup de travail. Il est néanmoins assez facile d’obtenir ce dont vous avez besoin pour des cas d’utilisation simples.

Par exemple, supposons que je construise un moteur de calcul en tant que classe et que je souhaite définir globalement la précision de la valeur de retour pour toutes les instances. Je souhaite une valeur par défaut lors de la compilation et, de temps en temps, il se peut que je souhaite l’ajuster plus bas pour traiter rapidement certains essais, puis l’ajuster plus haut pour mon travail final. Un atsortingbut de classe est fabriqué sur commande, mais vous pouvez obtenir la fonctionnalité dont vous avez besoin dans cython comme suit:

Tout d’abord, définissez au niveau du module les éléments suivants:

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

L’utilisation d’un tableau nous permet d’utiliser la precision[0] cython precision[0] équivalente à la *precision C *precision . La precision nom cdef est implicitement un pointeur puisque l’élément de données est un tableau. Cela permet d’utiliser les idiomes syntaxiques de cython pour convertir des emplacements de stockage de cython en références python. Si tout ce que vous voulez, c’est une constante globale accessible par le code cdef de l’une des classes du module, vous avez terminé. Si vous voulez l’utiliser ssortingctement en tant qu’atsortingbut de classe, vous devez appliquer cette discipline – le compilateur s’en fiche.

Maintenant, si vous souhaitez également ajuster la valeur du code python , vous aurez besoin d’une paire de fonctions cdef que le code python du module peut appeler pour accéder à l’atsortingbut:

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

À ce stade, la sémantique varie un peu du python pur, à moins que vous ne vouliez vraiment transpirer. Vous avez besoin d’un setter et d’un getter python , et je trouve le protocole de descripteur python implémenté par les propriétés le plus simple:

 cdef class SomeCalculator: ... property precision: def __get__(self): """Get or set calculation precision, default == 8. This is like a class atsortingbute: 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))) 

Le premier obtient une référence python à l’atsortingbut. La seconde définit l’atsortingbut avec une valeur intégrale python , contrôlée pour se situer dans les limites. L’ cython appel et de retour de fonction cython prend automatiquement en charge les conversions, qui sont plus complexes qu’elles ne le paraissent.

Par exemple, get_precision retourne un C-pointer . Si vous avez effectué la déréférencement dans get_precision vous obtiendrez une erreur en essayant de renvoyer un C-int dans __get__ comme s’il s’agissait de python . Si, au lieu de cela, vous __get__ simplement le déréférencement [0] dans __get__ vous obtiendrez une erreur en essayant de renvoyer un C-pointer comme s’il s’agissait d’un python int . Tel qu’écrit, les conversions automatiques correspondent correctement aux types. cython est très pointilleux à propos de ce genre de choses et peut retourner en silence des valeurs incorrectes, découvrables uniquement à l’exécution. Il peut falloir des expériences pour déduire la bonne incantation.

La docssortingng vous dit de ne pas attendre un atsortingbut de classe python pur. Si vous souhaitez créer des sous-classes et que celles-ci utilisent un paramètre global différent, vous devrez transpirer un peu plus. En python , tout cela se fait automatiquement.

Même dans ce cas, il existe d’autres différences. Un atsortingbut de classe réel peut être référencé sur la classe ou sur une instance. Cette propriété ne peut être référencée que sur une instance. La définition d’un atsortingbut de classe réel sur l’instance crée une copie spécifique à l’instance, laissant cet atsortingbut intact, mais invisible pour l’instance modifiée.

Pour le cas d’utilisation donné, cela fonctionne. Un atsortingbut de classe réel est inutile. Comme le code de cython est généralement moins abstrait et demande beaucoup d’informatique, cette approche minimale suffit souvent.

Bien qu’il ne semble pas possible d’avoir des atsortingbuts statiques de type C, les types d’extension Cython peuvent avoir des atsortingbuts statiques Python normaux, qui sont également automatiquement accessibles en Python. Déclarez-les simplement comme vous les déclareriez en Python:

 cdef class Foo: bar = 4 

Le code généré montre que ces atsortingbuts statiques sont stockés en tant qu’objects Python dans l’atsortingbut dict de l’object classe, c’est-à-dire que si vous les utilisez dans des contextes où les types C sont utilisés, ils sont reconvertis à partir d’objects Python.

Vous ne pouvez pas faire ça comme ça. Je ne sais pas si les atsortingbuts statiques sont supportés, mais les atsortingbuts “normaux” doivent être accédés à partir de méthodes, par exemple un constructeur:

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