+ Rispondi al messaggio
Visualizzazione dei risultati da 1 a 8 su 8

Cython: Uso di cinit vs init

  1. #1
    ery
    ery non è in linea Novello
    Ciao!
    Ho un problema con cython per quato riguarda l'uso di init e cinit durante la derivazione delle classi
    All'inizio usavo il cinit in tutt e due *.pyx in quella base e in quella derivata,
    e quando creavo una instanza della classe inherited
    si chiamava prima quello della base.pyx con tutti gli argomenti passati nella Derived.pyx
    ma visto che la derivata prende più argomenti della classe base,causava problemi.
    Cosi ho pensato di utilizzare i metodi abstract come in python,e usare init in tutte e 2 le classi,e cinit
    non faceva più nulla,ma pure questo non funziona visto che gli abstract si usano solo in python.
    In tutti questi casi fa aborted alla fine.

    Quindi quello che io voglio fare è: instanziando la classe derivata
    nel momento che passo al cinit della classe base passo nei metodi della classe derivata,quindi nn creo piu un
    oggetto della classe base che contiene solo il nome( ad esempio),ma uno della classe derivata che contiene nome e eta.


    PS: ho letto in doc di cython dove sugerivano di usare nel cinit *arg e **kwargs ma non ho potuto trovare nessun
    esmprio pratico di come si poteva fare.

    Quale di questi è meglio usare?
    Grazie!

  2. #2
    L'avatar di Master85
    Master85 non è in linea Moderatore Globale Ultimo blog: Eclipse: Un IDE per PHP e Python
    Ciao ery,
    benvenuto in MasterDrive.it, se non lo hai ancora fatto ti consiglio vivamente di leggere la nostra Netiquette.

    Quote Originariamente inviato da ery
    ...All'inizio usavo il cinit in tutt e due *.pyx in quella base e in quella derivata,
    e quando creavo una instanza della classe inherited
    si chiamava prima quello della base.pyx con tutti gli argomenti passati nella Derived.pyx
    ma visto che la derivata prende più argomenti della classe base,causava problemi...
    __init__ e __cinit__ vengono utilizzati per scopi ben precisi, non possono essere interscambiati a piacere, ti consiglio di approfondire l'argomento in questa pagina: Using C Libraries. Cito la parte relativa a __cinit__ direttamente dalla pagina segnalata:

    Quote Originariamente inviato da Cython Doc - Using C Libraries
    While __init__ is available as well, it is not guaranteed to be run (for instance, one could create a subclass and forget to call the ancestor’s constructor). Because not initializing C pointers often leads to hard crashes of the Python interpreter, Cython provides __cinit__ which is always called immediately on construction, before CPython even considers calling __init__, and which therefore is the right place to initialise cdef fields of the new instance. However, as __cinit__ is called during object construction, self is not fully constructed yet, and one must avoid doing anything with self but assigning to cdef fields
    Dal momento che da quanto hai scritto pare che il problema riguarda prettamente l'ereditarietà, ti invito a pubblicare qualche pezzetto di codice più specifico del tuo problema.
    Senza avere la possibilità di capire dov'è il tuo errore è difficile poterti fornire suggerimenti utili .
    Ultima modifica di Master85; 12-12-2011 21:13 

  3. #3
    ery
    ery non è in linea Novello
    La parte di Person è quasi uguale a quella che cè sulla Documentation di cython la queue.pyx

    Allora avendo:
    un file.h ,un Private_file.h e un Person.c ho creato il
    Person.pyx
    cdef extern from "Person.h":
        cdef struct Person_TAG:
            pass
        ctypedef Person_TAG* Person_ptr
    
        Person_ptr Person_create(char* name)
        void Person_destroy(Person_ptr self)
        char* Person_get_name(Person_ptr self)
        int Person_get_age(Person_ptr self)
        void Person_birthday(Person_ptr self)
        
    cdef class Person:
        cdef Person_ptr P_create
    
        def __cinit__(self, char* name):
            self.P_create = Person_create(name)
            if self.P_create is NULL:
                raise MemoryError
            print "Person %s created" % name
            return
    
        def __dealloc__(self):
            if self.P_create is not NULL:
                print "Destroying Person %s" % self.name
                Person_destroy(self.P_create)
                pass
            return
    
        property name:
            def __get__(self):
                return Person_get_name(self.P_create)
    
        property age:
            def __get__(self):
                return Person_get_age(self.P_create)
    
        def birthday(self):
            Person_birthday(self.P_create)
    
    poi devo creare un Student.pyx che eredita da Person.pyx
    e anche per Student ho il file.h,Private_file.h e Student.c
    quello che ho fatto io su Student.pyx è:

    Student.pyx
    from Personpy cimport Person
    from Personpy cimport Person_ptr
    
    cdef class Student (Person):
       
    
        cdef extern from "Student.h":
        ctypedef struct Student_TAG:
          pass
        ctypedef Student_TAG* Student_ptr
    
        Student_ptr Student_create(char* name, int age)
        void Student_destroy(Student_ptr self)
        double Student_get_average(Student_ptr self)
        void Student_sit_exam(Student_ptr self, double exam_result)
    
        def __cinit__(self, char* name,int age):   #----->qua cè il problema
            self.obj = <Person_ptr> Student_create(name, age)
            if self.obj is NULL:
                raise MemoryError
            print "Student %s created %d" % name  % age
            return
    
        def __dealloc__(self):
            if self.obj is not NULL:
                print "Destroying Student %s" % self.name
                Student_destroy( <Student_ptr> self.obj)
                pass
            return
    
        property average:
          def __get__(self):
            return Student_get_average( <Student_ptr> self.obj)
    
        def Student_sit_exam(self,double exam_result):
            Student_sit_exam( <Student_ptr> self.obj, exam_result)
    
    e nel Student.pyx succede quello che ho descritto sopra,
    il cinit della Person si chiama automaticamente e di conseguenza quando io faccio:
    >import Studentpy #che è la libreria dinamica Studentpy.so
    >s = Studentpy.Student()
    mi dice che cinit prende un solo parametro,ovvio perche è il cinit di Person
    cosa che io non voglio che succeda,perche voglio creare un Student che prende 2 prametri.

    ps: grazie del benvenuto , già lette le regole

  4. #4
    L'avatar di Master85
    Master85 non è in linea Moderatore Globale Ultimo blog: Eclipse: Un IDE per PHP e Python
    Ciao Ery,

    il progetto Cython nasce essenzialmente per soddisfare tre necessità della programmazione Python: 1) Estendere l'interprete Python attraverso moduli compilati in binario (vedesi librerie per il calcolo numerico ad esempio); 2) Possibilità di creare wrapper tra Python e librerie preesistenti scritte in C/C++ (vedesi strutture dati ottimizzate (liste, alberi, grafi, etc etc)); 3) Individuare e ottimizzare parti critiche di un programma Python: definire in modo statico determinate variabili, migliorare il tempo di esecuzione dei loops, operazioni I/O, calcoli matematici, utilizzo della memoria e così via.

    L'esempio che hai proposto (un ibrido tra un tentativo di wrapper ed ereditarietà), o meglio, l'utilizzo del Cython che stai facendo non passa per nessuno dei punti sopra indicati. Piuttosto, stai cercando di tradurre un comune programma OOP di Python (argomento in questione: ereditarietà e wrapper) in Cython. Cosa abbastanza inutile e confusionaria.

    D'altra parte, al di là dell'esempio proposto, il problema che presenta il tuo codice sta nelle chiamate a __cinit__. Questo particolare costruttore viene chiamato una sola volta al momento dell'istanziazione di una classe e prima dell'__init__ e prima che l'oggetto stesso sia realmente disponibile (evitare chiamate ad attributi o metodi dell'oggetto, all'interno di __cinit__). È utilizzato in via speciale quando è necessario eseguire particolari operazioni di allocazione della memoria e inizializzazione di determinate variabili (ovviamente statiche). Nel tuo caso, il costruttore __cinit__ della classe derivata, chiama prima il costruttore della classe base e successivamente quello corrente (attenzione: non è possibile chiamare esplicitamente il costruttore della classe base e la lista degli argomenti dei due costruttori non puo' essere diversa).

    Se intendi cambiare il comportamento dei due costruttori, devi ricorrere a __init__. Ma ripeto, la strada che hai intrapreso è assolutamente sbagliata in partenza .

    Es. Parent e Child type in Cython (ereditarietà in Cython con __init__)

    """
    ParentClass Example
    """
    cdef class ParentClass:

    cdef char* _nome
    cdef char* _cognome

    def __init__(self, char* n, char* c):
    print "Parent class constructor called"
    self._nome = n
    self._cognome = c

    def get_nome(self):
    return self._nome

    def get_cognome(self):
    return self._cognome

    """
    ChildClass Example
    """
    cdef class ChildClass(ParentClass):

    cdef char* _email

    def __init__(self, char* n, char* c, char* e):
    super(ChildClass, self).__init__(n, c)

    print "Child class constructor called"
    self._email = e

    def get_email(self):
    return self._email

    Un piccolo esempio di ereditarità in Cython (in buona sostanza è Python ma con qualche tipo di dato statico)
    Ultima modifica di Master85; 12-12-2011 21:15 

  5. #5
    ery
    ery non è in linea Novello
    Lo so che è un esempio "inutile" ma siccome ho deciso che lavorero sul wrapper,ho deciso di fare delle prove su un esempio semplice,giusto per creare un po l'idea prima di metermi sul serio.
    L'esempio è abbastanza capibile,ma nel mio caso non funziona,mi da segmentation fault
    Non avresti qualche sugerimento da darmi nel usare il cinit,pensa sempre che io sono interesato al secondo punto: (2)Possibilità di creare wrapper tra Python e librerie preesistenti scritte in C/C++

  6. #6
    L'avatar di Master85
    Master85 non è in linea Moderatore Globale Ultimo blog: Eclipse: Un IDE per PHP e Python
    Quote Originariamente inviato da ery Visualizza il messaggio
    ...Non avresti qualche sugerimento da darmi nel usare il cinit...
    Se leggi bene la mia ultima risposta, credo di averti fornito indicazioni abbastanza complete sull'utilizzo del __cinit__. Non è una questione di esempi, bensì capire dove e quando utilizzarlo, e anche questo caso è spiegato nella risposta precedente. Maggiori approfondimenti li trovi sul sito ufficiale di Cython. Dovresti iniziare sicuramente a mettere ordine scrivendo del codice di esempio più concreto (ad esempio: un wrapper tra Python ed una libreria scritta C per specifiche strutture dati).

  7. #7
    ery
    ery non è in linea Novello
    Ok,ti chiedo un ultima cosa.
    Quello che ho fatto adesso è cambiare in tutte e due le classi il cinit a init.
    Su init si possono fare le chiamate ai metodi? E se io non chiamo esplecitamente il init della classe base ,
    si esegue solo il init della classe derivata e il problema e risolto,giusto?
    Ma non funziona,mi da segmentation fault , e non lo capisco perche.

  8. #8
    ery
    ery non è in linea Novello
    Risolto ho usato l'overraiding.
    Grazie mille per le informazioni in su

+ Rispondi al messaggio

Potrebbero interessarti anche ...

  1. Risposte: 1
    Ultimo Post: 17-10-2011, 11:05
  2. Risolto: Ubuntu: Target filesystem doesn't have sbin/init
    Da Pimax1985 nel forum Tutto Linux
    Risposte: 1
    Ultimo Post: 09-03-2011, 17:05
  3. init
    Da nandela nel forum Presentati
    Risposte: 1
    Ultimo Post: 16-08-2010, 16:59
  4. init string modem multitech
    Da nitrotnt nel forum Altri linguaggi e strumenti
    Risposte: 0
    Ultimo Post: 07-07-2006, 10:27
  5. Articolo: System V Init
    Da Maxell1985 nel forum Tutto Linux
    Risposte: 0
    Ultimo Post: 17-11-2005, 19:30