2015-01-19 11 views
7

Próbuję rozszerzyć istniejące źródło python o cython .pxd, jak Stefan Behnel ilustruje na slajdach od 32 do 35 z "Using the Cython Compiler to write fast Python code".Metaclass Cython .pxd: Jak powinienem wdrożyć `__eq __()`?

W ramach ćwiczenia uderzam w ścianę metodą __eq__() w metaclassie. Chciałbym móc wybrać prostszy przypadek, aby uruchomić Cython, ale mój kod produkcyjny nie jest taki prosty. Przygotowałem "minimalny, kompletny przykład", aby zilustrować problem ... zobacz kod na dole pytania.

Krótka historia ...

  • Jeśli używam cdef inline __richcmp__(Japan_Car_ABC self, Japan_Car_ABC other, int op):, Cython zarzuca Special methods must be declared with 'def', not 'cdef'
  • Jeśli używam def __richcmp__(Japan_Car_ABC self, Japan_Car_ABC other, int op):, Cython zarzuca function definition in pxd file must be declared 'cdef inline'

Więc Cython daje mi mylące wskazówki ...

Pytania:

  • wiem, że pure-python .pxd pliki mają ograniczeń; definiuje __richcmp__() w moim .pxd prawidłowy sposób korzystania z .pxd w celu wzmocnienia czystego Pythona?
  • Jeśli jest to prawidłowy sposób korzystania z .pxd, jak mogę to naprawić, aby poprawnie skompilować?
  • Jeśli jest to błędne, czy .pxd może wzbogacić mój czysty metaklak Pythona, bez ponownego zapisywania całego metaklasu w pliku .pyx? (Przykład: class Card in this project)

To jest mój .pxd ...

### File: car_abc.pxd 
# cython: infer_types=True 
cimport cython 

cdef class Japan_Car_ABC: 
    cpdef public char* model 
    cpdef public char* color 

    def __richcmp__(Japan_Car_ABC self, Japan_Car_ABC other, int op): 
     """Ref: http://docs.cython.org/src/userguide/special_methods.html#rich-comparisons""" 
     if op==2: 
      # op==2 is __eq__() in pure python 
      if self.model==other.model: 
       return True 
      return False 
     else: 
      err_msg = "op {0} isn't implemented yet".format(op) 
      raise NotImplementedError(err_msg) 

informacyjne:

car_abc.py:

### File: car_abc.py 
from abc import ABCMeta 

class Japan_Car_ABC(object): 
    __metaclass__ = ABCMeta 

    def __init__(self, model="", color=""): 
     self.model = model 
     self.color = color 

    def __eq__(self, other): 
     if self.model==other.model: 
      return True 
     return False 

    def __hash__(self): 
     return hash(self.model) 

car.py :

from car_abc import Japan_Car_ABC 

class Lexus(Japan_Car_ABC): 
    def __init__(self, *args, **kwargs): 
     bling = kwargs.pop("bling", True)  # bling keyword (default: True) 
     super(Lexus, self).__init__(*args, **kwargs) 
     self.bling = bling 

class Toyota(Japan_Car_ABC): 
    def __init__(self, *args, **kwargs): 
     super(Toyota, self).__init__(*args, **kwargs) 


if __name__=="__main__": 
    gloria_car = Lexus(model="ES350", color="White") 
    jeff_car = Toyota(model="Camry", color="Silver") 
    print("gloria_car.model: {0}".format(gloria_car.model)) 
    print("jeff_car.model: {0}".format(jeff_car.model)) 
    print("gloria_car==jeff_car: {0}".format(gloria_car==jeff_car)) 

setup.py:

from distutils.core import setup 
from distutils.extension import Extension 
from Cython.Distutils import build_ext 

ext_modules = [Extension("car_abc", ["car_abc.py"]), 
    #Extension("car", ["car.py"]), 
    ] 

setup(
    name = "really build this thing", 
    cmdclass = {'build_ext': build_ext}, 
    ext_modules = ext_modules 
) 

Odpowiedz

3

prosta odpowiedź (otrzymane Nils Bruin poprzez cython-users) jest to, że PXD nie może być stosowany do implementacji metod (takich jak __richcmp__()). Ponieważ używam metaclass, muszę przenieść mój kod do pliku .pyx, więc mogę zaimplementować __richcmp__() i inne specjalne metody cythonowe.

Powiązane problemy