o_y*_*eah 5 python oop class cython
代码块 1 使用 __init__
%%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())
Run Code Online (Sandbox Code Playgroud)
代码块 2 使用 __cinit__
%%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())
Run Code Online (Sandbox Code Playgroud)
我测试了这两个代码,并且都运行没有错误。在这种情况下,使用__cinit__而不是有__init__什么意义?
看了官方文章,被一句话搞糊涂了:
如果需要将修改后的参数列表传递给基类型,则必须在方法中执行相关部分的初始化
__init__(),其中适用于调用继承方法的正常规则。
“修改后的论点”是什么意思?在这里,为什么我应该使用 init 而不是 cinit?
主要是关于继承。假设我从你的班级继承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
Run Code Online (Sandbox Code Playgroud)
如何__init__最终被调用完全取决于从它继承的类。请记住,可能存在多层继承。
此外,创建包装 C/C++ 对象的类的一个相当常见的模式是创建一个staticmethod cdef函数作为替代构造函数:
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
Run Code Online (Sandbox Code Playgroud)
在这种情况下,__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)
Run Code Online (Sandbox Code Playgroud)
即NamedHelloPlus1控制什么参数NamedValue得到。使用__cinit__Cython,所有调用都__cinit__接收完全相同的参数(因为 Cython 安排了调用 - 您不能手动调用它)。