Typing Extension Type Object

68 views
Skip to first unread message

Sebastian Raab

unread,
Jan 31, 2025, 8:28:18 AMJan 31
to cython-users
Hi all,
given the following example:

cdef class MyClass:
    cdef public int a
    cdef public list classes
   
    def __init__(self):
        self.a = 1
        self.classes = []
       
        current_class = self.__class__
        while True:
            self.classes.append(current_class)
           
            if current_class is MyClass:
                break
           
            current_class = current_class.__base__
       

    cpdef void do_something(self):
        self.a = self.a+1
       
   
    cpdef void do_all_somethings(self):
        for i in range(len(self.classes)):
            class_: type[MyClass] = self.classes[i]
            class_.do_something(self)


cdef class MyInheritedClass(MyClass):
   
    cpdef void do_something(self):
        self.a = self.a+2
       


instance = MyInheritedClass()
instance.do_all_somethings()



       
The execution of this works all fine. But unfortnuately, typing the object returned by the list does not seem to work (in any way I tried it so far, here as python type annotation), as I can see in the yellow html line for class_.do_something(self).

Can anyone tell me how to type it properly?

Thanks and best regards
Sebastian

Peter Schay

unread,
Jan 31, 2025, 8:36:40 AMJan 31
to cython...@googlegroups.com
Hi,
Cython parses Python type annotations but does not use them for too many things (the documentation has a section on it, IIRC).
In this case a Cython declaration is required.

Declare a cdef pointer-ish thing before the for loop:
  cdef Myclass class_

and then assign it and use it
   class_ = self.classes[i]


--

---
You received this message because you are subscribed to the Google Groups "cython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cython-users...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/cython-users/70532002-4196-4c26-952b-0580f7fbc869n%40googlegroups.com.

Sebastian Raab

unread,
Jan 31, 2025, 2:30:53 PMJan 31
to cython-users
Hi,
thanks for your answere.
Unfortunately I am not very experienced with pointers, I have no idea how to do it (and all I tried failed).
Can you please give me an example?

Peter Schay

unread,
Jan 31, 2025, 2:38:29 PMJan 31
to cython...@googlegroups.com
Hi,
This should work:

    cpdef void do_all_somethings(self):
        cdef MyClass class_
        for i in range(len(self.classes)):
            class_ = self.classes[i]
            class_.do_something()



Sebastian Raab

unread,
Feb 1, 2025, 2:51:00 PMFeb 1
to cython-users
Hi,
thanks, but I think this does not fit to my initial code.
You are assuming, that the self.classes list contains instances of the MyClass class. But it contains the class MyClass and a the derived class MyIneritedClass, not instances of them.
So cdef MyClass class_ is not working.

da-woods

unread,
Feb 1, 2025, 2:52:59 PMFeb 1
to cython...@googlegroups.com
On 01/02/2025 19:48, Sebastian Raab wrote:
Hi,
thanks, but I think this does not fit to my initial code.
You are assuming, that the self.classes list contains instances of the MyClass class. But it contains the class MyClass and a the derived class MyIneritedClass, not instances of them.
So cdef MyClass class_ is not working.


That should work. What's the specific problem?

da-woods

unread,
Feb 1, 2025, 3:23:12 PMFeb 1
to cython...@googlegroups.com

Ah sorry - I misread what you said.

I'm not sure that what you're trying to is possible I'm afraid.

This is a case where you're trying to do something both very dynamically (as if you were using Python) but also taking advantage of Cython's compile-time static typing. Unfortunately this kind of code typically just doesn't work because it's trying to mix two incompatible things, and you have to accept the "yellow highlighting".

Prakhar Goel

unread,
Feb 2, 2025, 12:53:20 AMFeb 2
to cython...@googlegroups.com
Also, have you considered just using super?

-- PG

On Sat, Feb 1, 2025, 15:06 Prakhar Goel <newt...@gmail.com> wrote:
Not sure if this is the source of the confusion but cdef classes aren't like Python classes. The fields you declared (e.g. self.classes) are instance attributes.

-- PG

Prakhar Goel

unread,
Feb 2, 2025, 12:53:32 AMFeb 2
to cython...@googlegroups.com
Not sure if this is the source of the confusion but cdef classes aren't like Python classes. The fields you declared (e.g. self.classes) are instance attributes.

-- PG

Sebastian Raab

unread,
Feb 2, 2025, 12:54:16 AMFeb 2
to cython-users
When using Peters example:

    cpdef void do_all_somethings(self):
        cdef MyClass class_
        for i in range(len(self.classes)):
            class_ = self.classes[i]
            class_.do_something()


I get the following error when executing:
TypeError: Cannot convert type to Tests.Cython_TypeClassVariable.type_class_variable.MyClass

However, in Peters example class._do_something() the self argument is missing, as class is not an instance itself. But when I change his example to:
    cpdef void do_all_somethings(self):
        cdef MyClass class_
        for i in range(len(self.classes)):
            class_ = self.classes[i]
            class_.do_something(self)

I get an error during compilation:
Error compiling Cython file:
------------------------------------------------------------
...


    cpdef void do_all_somethings(self):
        cdef MyClass class_
        for i in range(len(self.classes)):
            class_ = self.classes[i]
            class_.do_something(self)
                               ^
------------------------------------------------------------

Tests\Cython_TypeClassVariable\type_class_variable.pyx:29:31: Call with wrong number of arguments (expected 1, got 2)

Sebastian Raab

unread,
Feb 2, 2025, 6:48:58 AMFeb 2
to cython-users
@D Woods:
Thanks! Knowing this already helps, so I'm not chasing something that's not possible.
This is only fine-tuning now. I am already more than happy with the enormous speedup I was able to achieve with cython - while still having lots of flexibility. You and the whole team do some really great work there, thank you all!

@Prakhar:
Right, I try to do something like super(), but without having inherited classes explicitly call super(). Actually my approach also turned out to be faster than super().

Prakhar Goel

unread,
Feb 2, 2025, 9:53:34 AMFeb 2
to cython...@googlegroups.com
Hmm... In that case, have you tried manually iterating through __class__.__mro__?

-- PG

--

---
You received this message because you are subscribed to the Google Groups "cython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cython-users...@googlegroups.com.

Sebastian Raab

unread,
Feb 3, 2025, 7:56:56 AMFeb 3
to cython-users
Yes I did, it is actually about the same that I do in my initial example. I did not use mro in my real code, because I implemented some more checks that decide, if I add a class to class_list.

@D Woods:
Just to make sure, an here an other approach. This time I assign methods to a list and want to use them later. The methods all do have the same signature. Do you still think, it is not possible to type them?

cdef class MyClass:
    cdef public int a
    cdef public list methods

   
    def __init__(self):
        self.a = 1
        self.methods = []

       
        current_class = self.__class__
        while True:
            self.methods.append(current_class.do_something)

           
            if current_class is MyClass:
                break
           
            current_class = current_class.__base__
       

    cpdef void do_something(self, int val):
        self.a = self.a + val
       
   
    cpdef void do_all_somethings(self):
        cdef xxxx method
        for i in range(len(self.methods)):
            method = self.methods[i]
            cast(xxxx, method)(self, 1)


cdef class MyInheritedClass(MyClass):
   
    cpdef void do_something(self, int val):
        self.a = self.a+2*val
       


instance = MyInheritedClass()
instance.do_all_somethings()

Stefan Behnel

unread,
Feb 17, 2025, 2:23:04 AMFeb 17
to cython...@googlegroups.com
Am 3. Februar 2025 11:04:28 UTC schrieb Sebastian Raab:
>Just to make sure, an here an other approach. This time I assign methods to
>a list and want to use them later. The methods all do have the same
>signature. Do you still think, it is not possible to type them?

Don't collect the Python method references. Instead, collect the object instances and then call the (C) methods on them in the loop.

Stefan

Reply all
Reply to author
Forward
0 new messages