【问题标题】:In Cython class, what's the difference of using __init__ and __cinit__?在 Cython 类中,使用 __init__ 和 __cinit__ 有什么区别?
【发布时间】:2020-07-10 04:52:36
【问题描述】:

使用__init__的代码块1

%%cython -3
cdef class c:
    cdef:
        int a
        str s
    def __init__(self):
        self.a=1
        self.s="abc"
    def get_vals(self):
        return self.a,self.s
m=c()
print(m.get_vals())

使用__cinit__的代码块2

%%cython -3
cdef class c:
    cdef:
        int a
        str s
    def __cinit__(self):  # cinit here
        self.a=1
        self.s="abc"
    def get_vals(self):
        return self.a,self.s
m=c()
print(m.get_vals())
  1. 我测试了这两个代码,都运行没有错误。 在这种情况下,使用__cinit__ 而不是__init__ 有什么意义?

  2. 看过官方文章,被一句话搞糊涂了:

    如果您需要将修改后的参数列表传递给基类型,则必须改为在 __init__() 方法中执行初始化的相关部分,其中调用继承方法的正常规则适用。

“修改参数”是什么意思?这里,为什么要使用 init 而不是 cinit?

【问题讨论】:

    标签: python class oop cython


    【解决方案1】:

    主要是关于继承。假设我继承自你的班级C

    class D(C):
        def __init__(self):
            pass  # oops forgot to call C.__init__
    
    class E(C):
        def __init__(self):
            super().__init__(self)
            super().__init__(self)  # called it twice
    

    __init__ 最终如何被调用完全取决于从它继承的类。请记住,可能存在多层继承。

    另外,a fairly common pattern for creating classes that wrap C/C++ objects is to create a staticmethod cdef function as an alternative constructor:

    cdef class C:
        def __cinit__(self):
            print("In __cinit__")
    
        @staticmethod
        cdef make_from_ptr(void* x):
            val = C.__new__(C)
            # do something with pointer
            return val
    

    在这种情况下,__init__ 通常不会被调用。

    相比之下,__cinit__ 保证只被调用一次,这在流程的早期阶段由 Cython 自动发生。当您的类依赖于被初始化的 cdef 属性(例如 C 指针)时,这一点最为重要。 Python 派生类甚至无法设置这些,但__cinit__ 可以确保它们是。

    在您的情况下,这可能无关紧要 - 使用您喜欢的任何一个。


    就“修改后的参数”而言,它是说你不能用__cinit__ 复制它:

    class NameValue:
         def __init__(self, name, value):
             self.name = name
             self.value = value
    
    class NamedHelloPlus1(NamedValue):
        def __init__(self, value):
            super().__init__("Hello", value+1)
    

    NamedHelloPlus1 控制 NamedValue 获取的参数。对于 __cinit__ Cython,所有对 __cinit__ 的调用都会收到完全相同的参数(因为 Cython 会安排调用 - 您不能手动调用它)。

    【讨论】:

      【解决方案2】:
      1. cinit 应该用于需要对对象进行 C 级初始化的地方。请注意这里,它们可能还不是一个完全有效的 python 对象。但是,在 cinit 中无法完成的任何事情都需要在 init 中完成。此时,所有对象都是有效的 python 对象。

      2. 如果我理解正确,它指向派生类中的可修改参数。参数列表的修改或解析方式可能与基本类型 init 不同。在这种情况下,需要使用 init。 This may be useful in giving you an insight on what I am trying to explain

      【讨论】:

        猜你喜欢
        • 2012-11-01
        • 2012-03-28
        • 1970-01-01
        • 1970-01-01
        • 2017-09-02
        • 1970-01-01
        • 2015-09-28
        • 2018-10-26
        • 1970-01-01
        相关资源
        最近更新 更多