got*_*nes 6 python inheritance cython
我正在尝试子类化pysam的Tabixfile
类并在实例化时添加其他属性.
class MyTabixfile(pysam.Tabixfile):
def __init__(self, filename, mode='r', *args, **kwargs):
super().__init__(filename, mode=mode, *args, **kwargs)
self.x = 'foo'
Run Code Online (Sandbox Code Playgroud)
当我尝试实例化我的MyTabixfile
子类时,我得到一个TypeError: object.__init__() takes no parameters
:
>>> mt = MyTabixfile('actn2-oligos-forward.tsv.gz')
Traceback (most recent call last):
File "<ipython-input-11-553015ac7d43>", line 1, in <module>
mt = MyTabixfile('actn2-oligos-forward.tsv.gz')
File "mytabix.py", line 4, in __init__
super().__init__(filename, mode=mode, *args, **kwargs)
TypeError: object.__init__() takes no parameters
Run Code Online (Sandbox Code Playgroud)
我也尝试Tabixfile
显式调用构造函数:
class MyTabixfile(pysam.Tabixfile):
def __init__(self, filename, mode='r', *args, **kwargs):
pysam.Tabixfile.__init__(self, filename, mode=mode, *args, **kwargs)
self.x = 'foo'
Run Code Online (Sandbox Code Playgroud)
但这仍然提高了TypeError: object.__init__() takes no parameters
.
这个类实际上是在Cython中实现的; 构造函数代码如下:
cdef class Tabixfile:
'''*(filename, mode='r')*
opens a :term:`tabix file` for reading. A missing
index (*filename* + ".tbi") will raise an exception.
'''
def __cinit__(self, filename, mode = 'r', *args, **kwargs ):
self.tabixfile = NULL
self._open( filename, mode, *args, **kwargs )
Run Code Online (Sandbox Code Playgroud)
我阅读了Cython文档__cinit__
并说明了__init__
这一点
传递给构造函数的任何参数都将传递给
__cinit__()
方法和__init__()
方法.如果您预计在Python中对扩展类型进行子类化,您可能会发现给出__cinit__()
方法*
和**
参数以便它可以接受并忽略额外的参数很有用.否则,具有__init__()
不同签名的任何Python子类都必须重写__new__()
1以及__init__()
Python类的编写者不希望必须执行的操作.
该pysam开发商并采取小心加*args
和**kwargs
的Tabixfile.__cinit__
方式,和我的子类__init__
的签名相匹配__cinit__
,所以我不明白为什么我不能重写的初始化Tabixfile
.
我正在使用Python 3.3.1,Cython v.0.19.1和pysam v.0.7.5进行开发.
aba*_*ert 17
这里的文档有点令人困惑,因为它假设您熟悉使用__new__
和__init__
.
该__cinit__
方法大致相当于__new__
Python中的方法.*
像__new__
,__cinit__
是不是你叫super().__init__
; 在Python甚至到达你的子类的__init__
方法之前调用它.之所以__cinit__
需要处理的子类的签名__init__
方法是完全一样的道理__new__
一样.
如果您的子类显式调用super().__init__
,那么__init__
再次查找超类中的方法,例如__new__
,a __cinit__
不是__init__
.所以,除非你也定义了一个__init__
,否则它会传递给object
.
您可以使用以下代码查看序列.
cinit.pyx:
cdef class Foo:
def __cinit__(self, a, b, *args, **kw):
print('Foo.cinit', a, b, args, kw)
def __init__(self, *args, **kw):
print('Foo.init', args, kw)
Run Code Online (Sandbox Code Playgroud)
init.py:
import pyximport; pyximport.install()
import cinit
class Bar(cinit.Foo):
def __new__(cls, *args, **kw):
print('Bar.new', args, kw)
return super().__new__(cls, *args, **kw)
def __init__(self, a, b, c, d):
print('Bar.init', a, b, c, d)
super().__init__(a, b, c, d)
b = Bar(1, 2, 3, 4)
Run Code Online (Sandbox Code Playgroud)
运行时,你会看到类似的东西:
Bar.new (1, 2, 3, 4) {}
Foo.cinit 1 2 (3, 4) {}
Bar.init 1 2 3 4
Foo.init (1, 2, 3, 4) {}
Run Code Online (Sandbox Code Playgroud)
所以,这里正确的解决方案取决于你想要做什么,但它是以下之一:
__init__
方法添加到Cython基类.super().__init__
完全取消通话.super().__init__
为不通过任何参数.__new__
向Python子类添加适当的方法.我怀疑在这种情况下它是你想要的#2.
*值得一提的是__cinit__
绝对不一样来__new__
.cls
你得到一个部分构造的self
对象(你可以信任__class__
和C属性,但不是Python属性或方法),而不是获取一个参数,__new__
MRO中所有类的方法都已经被调用了__cinit__
; 在__cinit__
你的基地被自动调用,而不是手动; 除了被请求的对象之外,你不会返回另一个对象; 它只是在它之前被调用__init__
,并且预期采用传递参数,就像__new__
它一样.