Cython и конструктори на класове

Имам проблем с използването на Cython на конструктори по подразбиране.

Моят C++ клас Node е следният

Node.h

class Node
{
public:
    Node()
    { 
        std::cerr << "calling no arg constructor" << std::endl;
            w=0.0;
        d=0.0;
    }
    Node(double val, double val2);
    {
            std::cerr << "calling 2 args constructor" << std::endl;
        this->w=val;
        this->d=val2;
    }
private:
    double d,w;
}

е обвит в Cython, както следва

cdef extern from "Node.h":
    cdef cppclass Node:
        Node() except +
        Node(double val1, double val2) except +
        double d
        double w

cdef class pyNode:
    cdef Node *thisptr      # hold a C++ instance which we're wrapping

    def __cinit__(self):
        self.thisptr = new Node()

    def __cinit__(self, double val1, double val2):
        self.thisptr = new Node(val1,val2)

    def __dealloc__(self):
        del self.thisptr

    def __repr__(self):
        return "d=%s w=%s" % (self.thisptr.w, self.thisptr.w )

Кодът на Cython се компилира добре, но особено когато се извиква от Python

from pyNode import pyNode as Node
n=Node(1.0,2.0)

Получавам очаквания низ calling 2 args constructor, но ако се опитвам да декларирам обект Node от python с помощта на конструктора „без аргументи“ (който трябва да бъде правилно деклариран като __cinit__(self), не получавам резултат, това означава, че аргументът без аргумент конструктор не се извиква!

Как мога изрично да го извикам от метода cinit на обвития клас?


person linello    schedule 02.11.2012    source източник


Отговори (1)


Проблемът тук е, че не можете да претоварвате __cinit__() така (тъй като само cdef функциите могат да бъдат overloaded) - вместо това, накарайте го да вземе стойности по подразбиране, след което извикайте правилното нещо, ако е необходимо.

Редактиране: По същество трябва да внедрите функцията по начин, по-близък до начина, по който бихте направили в нормален код на Python, вместо да използвате претоварване:

def __cinit__(self, double val1=-1, double val2=-1): 
    if val1 == -1 or val2 == -1:
        self.thisptr = new Node()
    else:
        self.thisptr = new Node(val1,val2)

Естествено, това предполага, че -1 е стойност, която не е полезна за функцията, можете да използвате друга стойност, или ако имате нужда всяка стойност на двойна да е валидна, тогава може да се наложи да премахнете въвеждането, като вземете обект на Python, така че че можете да използвате None по подразбиране:

def __cinit__(self, val1=None, val2=None):
    if val1 is not None and val2 is not None:
        self.thisptr = new Node(val1, val2)
    else:
        self.thisptr = new Node()
person Gareth Latty    schedule 02.11.2012
comment
И така, как предлагате да промените кода? Не разбрах предложението ви, трябва ли да премахна cinit и да оставя на cython да го декларира вместо мен? - person linello; 02.11.2012
comment
Имайте предвид обаче, че това има донякъде неприятния страничен ефект, че Node(5) работи и извиква конструктора с два аргумента с 5, -1; може да искате да проверите за това. И разбира се, въз основа на кода на C++ тук, използвайки 0 като стойности по подразбиране (и след това само извикване на конструктора с два аргумента) ще има същия ефект. - person Danica; 02.11.2012
comment
@Dougal Предполагайки, че никога няма да промените това, което прави конструкторът по подразбиране. Редактиране: И добави or, за да гарантира, че и двете стойности са зададени. - person Gareth Latty; 02.11.2012
comment
Благодаря, вече е ясно! Това заобиколно решение ли е или желана функция? (Работя основно в C++, така че този вид неща изглеждат странни) - person linello; 02.11.2012
comment
В Python няма смисъл да се претоварват функции (тъй като типовете не са важни, така че няма да има диференциация, освен броя на аргументите, който се обработва по-добре от стойностите по подразбиране), така че претоварването не съществува. Cython добавя това за cdef функции, но не и за функции на Python като __cinit__(). - person Gareth Latty; 02.11.2012
comment
Благодаря за полезното обяснение! - person linello; 02.11.2012
comment
Ами ако val1 и val2 не са от търсения тип? Как да уточня, че трябва да са два double, а не например два списъка? - person linello; 02.11.2012
comment
В този момент ще получите изключение, тъй като се опитва да конвертира стойностите за функцията c. - person Gareth Latty; 03.11.2012
comment
Какво ще стане, ако променя функцията си с помощта на type(val1) is int and type(val2) is float - person linello; 03.11.2012
comment
@linello Това няма да има значение. - person Gareth Latty; 03.11.2012
comment
Връзката е мъртва. - person RestInPeace; 20.05.2019
comment
@RestInPeace Те преместиха wiki в github, актуализираха. - person Gareth Latty; 20.05.2019