Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] derived method not called from within __cinit__ #4004

Open
Timtam opened this issue Feb 12, 2021 · 2 comments
Open

[BUG] derived method not called from within __cinit__ #4004

Timtam opened this issue Feb 12, 2021 · 2 comments

Comments

@Timtam
Copy link

Timtam commented Feb 12, 2021

Describe the bug
I'm not actually sure if that is supposed to not work, but its not documented, so either it should be added to the docs or be considered a bug.
Anyway, when having two extension types, one inheriting the other and deriving a method, e.g. a cdef one, which gets called within the base class's cinit() method, the derived method doesn't get called.
To Reproduce
Code to reproduce the behaviour:

cdef class Foo:

  def __cinit__(self):
    self.talk()

  cdef void talk(self):
    print("i'm talking")

cdef class Bar(Foo):

  cdef void talk(self):
    print("now you're talking!")
    

Expected behavior
I'd expect it to print "now you're talking!", instead of printing "i'm talking".
A rather obvious solution would be to switch from cinit() to init() here (at least i'd expect that to work, didn't try it yet though). I'm using this "feature" to initialize different attributes of my class, the subtype having more attributes than the base class, therefore the subtype derives the initialization cdef method to initialize all of its additional attributes. I just noticed that this never happens due to the base class only calling its own cdef instead of the derived ones.

Environment (please complete the following information):

  • OS: tested on Windows 10
  • Python version 3.8.2
  • Cython version 3.0a6
@da-woods
Copy link
Contributor

da-woods commented Feb 12, 2021

I wouldn't expect this to work or consider it a bug. You're right that it isn't explicitly documented though and a PR to correct this would probably be welcome.

The call order is roughly: "base __cinit__"->"derived __cinit__"->"__init__ functions as defined by Python". Therefore base __cinit__ is called very early and has basically no knowledge that it might be in a derived class. If you're familiar with C++ then I believe that virtual functions in C++ constructors work very similarly.

I would expect your suggestion of moving code to __init__ to work. A single class can have both a __cinit__ or __init__ method so you can use them both as needed.

@scoder
Copy link
Contributor

scoder commented Feb 14, 2021

The virtual function table of the subclass probably isn't initialised yet at this point. That's reasonable, because __cinit__() is called on the way back from Python's object allocator. If it's not documented yet, then it's worth stating somewhere that the code in __cinit__() must not touch (or use) the state of subclasses, since they are not initialised yet when it is called.

I consider the behaviour undefined in this case. You should not do this.

As suggested, use __init__() for anything that requires a fully initialised object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants