python - Can't override __init__ of class from Cython extension -


i trying subclass pysam's tabixfile class , add additional attributes on instantiation.

class mytabixfile(pysam.tabixfile):      def __init__(self, filename, mode='r', *args, **kwargs):         super().__init__(filename, mode=mode, *args, **kwargs)         self.x = 'foo' 

when try instantiate mytabixfile subclass, 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 

i tried calling tabixfile constructor explicitly:

class mytabixfile(pysam.tabixfile):      def __init__(self, filename, mode='r', *args, **kwargs):         pysam.tabixfile.__init__(self, filename, mode=mode, *args, **kwargs)         self.x = 'foo' 

but still raises typeerror: object.__init__() takes no parameters.

this class implemented in cython; constructor code below:

cdef class tabixfile:     '''*(filename, mode='r')*      opens :term:`tabix file` reading. missing     index (*filename* + ".tbi") raise exception.     '''     def __cinit__(self, filename, mode = 'r', *args, **kwargs ):         self.tabixfile = null         self._open( filename, mode, *args, **kwargs ) 

i read through cython documentation on __cinit__ , __init__ says

any arguments passed constructor passed both __cinit__() method , __init__() method. if anticipate subclassing extension type in python, may find useful give __cinit__() method * , ** arguments can accept , ignore arguments. otherwise, python subclass has __init__() different signature have override __new__() 1 __init__(), writer of python class wouldn’t expect have do.

the pysam developers did take care add *args , **kwargs tabixfile.__cinit__ method, and subclass __init__ matches signature of __cinit__ not understand why i'm unable override initialization of tabixfile.

i'm developing python 3.3.1, cython v.0.19.1, , pysam v.0.7.5.

the documentation little confusing here, in assumes you're familiar using __new__ , __init__.

the __cinit__ method equivalent __new__ method in python.*

like __new__, __cinit__ not called super().__init__; it's called before python gets subclass's __init__ method. reason __cinit__ needs handle signature of subclass __init__ methods exact same reason __new__ does.

if subclass explicitly call super().__init__, looks __init__ method in superclass—again, __new__, __cinit__ not __init__. so, unless you've also defined __init__, pass through object.


you can see sequence following code.

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) 

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) 

when run, you'll see like:

bar.new (1, 2, 3, 4) {} foo.cinit 1 2 (3, 4) {} bar.init 1 2 3 4 foo.init (1, 2, 3, 4) {} 

so, right fix here depends on you're trying do, it's 1 of these:

  1. add __init__ method cython base class.
  2. remove super().__init__ call entirely.
  3. change super().__init__ not pass params.
  4. add appropriate __new__ method python subclass.

i suspect in case it's #2 want.


* it's worth noting __cinit__ isn't identical __new__. instead of getting cls parameter, partially-constructed self object (where can trust __class__ , c attributes not python attributes or methods), __new__ methods of classes in mro have been called before __cinit__; __cinit__ of bases gets called automatically instead of manually; don't return different object besides 1 that's been requested; etc. it's it's called before __init__, , expected take pass-through parameters, in same way __new__ is.


Comments

Popular posts from this blog

c# - Send Image in Json : 400 Bad request -

jquery - Fancybox - apply a function to several elements -

An easy way to program an Android keyboard layout app -