Trying to pass an instance of a derived class to a function which accepts instances of the superclass gives an error in Cython v3.0.0a11
:
test.pyx
:
class MyInt(int):
pass
def takes_int(a: int):
pass
try.py
:
from test import takes_int, MyInt
takes_int(MyInt(1))
try.py OUTPUT
:
Traceback (most recent call last):
File "C:\Users\LENOVO PC\PycharmProjects\MyProject\cython_src\try.py", line 3, in <module>
takes_int(MyInt(1))
TypeError: Argument 'a' has incorrect type (expected int, got MyInt)
Changing to v0.29.32
, cleaning the generated C
file and the object files, and re-running, gets rid of the error.
CodePudding user response:
This is (kind of) expected.
Cython has never allowed subtype polymorphism for builtin type arguments. See https://cython.readthedocs.io/en/latest/src/userguide/language_basics.html#types:
This requires an exact match of the class, it does not allow subclasses. This allows Cython to optimize code by accessing internals of the builtin class, which is the main reason for declaring builtin types in the first place.
This is a restriction which applies only to builtin types - for Cython defined cdef
classes it works fine. It's also slightly different to the usual rule for annotations, but it's there because it's the only way that Cython can do much with these annotation.
What's changed is that an int
annotation is interpreted as "any object" in Cython 0.29.x and a Python int
in Cython 3. (Note that cdef int
declares a C int though.) The reason for not using an int
annotation in earlier versions of Cython is that Python 2 has two Python integer types, and it isn't easy to accept both of those and usefully use the types.
I'm not quite sure exactly what the final version of Cython 3 will end up doing with int
annotations though.
If you don't want Cython to use the annotation (for example you would like your int class to be accepted) then you can turn off annotation_typing
locally with the @cython.annotation_typing(False)
decorator.