#🔒 [ctypes] When creating a array, why it doesn't call any magic methods?

27 messages · Page 1 of 1 (latest)

arctic forum
#

I want to create a class that inherits from c_void_p and adds some behavior to it.
I need to inherit from it to support this "special" syntax: https://docs.python.org/3/library/ctypes.html#arrays.
When I create an array of MY_CLASS, it doesn’t seem to call any magic methods. Why is that, and what can I do about it?

from ctypes import c_void_p


class MY_CLASS(c_void_p):

    def __init__(self, own: bool):
        print("init called")
        super().__init__()
        self.own = own        

    def __new__(cls, *args, **kwargs):
        print(f"new called with args={args}, kwargs={kwargs}")
        return super().__new__(cls)

    def __call__(self, own: bool):
        print("call called")
        self.own = own

    def __del__(self):
        print("del called")
        if self.own:
            # do something here one day
            pass

def main():
    print("Initialize MY_CLASS directly")
    # This calls __new__, __init__, and __del__
    MY_CLASS(False)

    print("Initialize an array of MY_CLASS")
    # This doesn’t call the __call__ method. Why?
    # Also, it doesn’t call the __del__ method. Why?
    my_array = (MY_CLASS * 5)(own=True)


if __name__ == "__main__":
    main()
brazen tinselBOT
#

@arctic forum

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

main tinsel
#

Because it looks like you're calling what you get when you multiply the class object,. At that point, you're not calling the instance of that class.

#
(MY_CLASS * 5)(own=True)```
Call of your class times 5, not call of your instance times 5.
#

!e ```py
class MyClass:
def call(self):
print('Call.')

instance = MyClass()
instance()

vs

(MyClass * 5)()```

brazen tinselBOT
main tinsel
#

Mind you, you are doing a lot of stuff I don't normally fiddle with, and I haven't ever really touched ctypes.

#

But that's what it looks like to me.

#

So you might need something like (MyClass * 5)()()

#

For your thing.

#

Hm. Not callable.

arctic forum
#

As you can see in this example (from here: https://docs.python.org/3/library/ctypes.html#callback-functions), it correctly set the value of each c_int:

from ctypes import c_int

IntArray5 = c_int * 5
ia = IntArray5(5, 1, 7, 33, 99)

print(ia)

So, I tought, there should be a way to replicate the behaviour, but with my class

main tinsel
#

Hm, sorry. I thought I'd spotted the problem.

#

Nevermind.

#

It may be possible that, especially given it's ctypes, there's some underlying automagical shenanigans going on that may disrupt any overloading.

#

Or I'm just dense.

#

Maybe _ctypes.PyCSimpleType, which is the type of c_void_p, implements __mul__ in a way where the resulting returned class doesn't implement __call__.

#

But the other methods get called...

#

That you've created.

#

Okay, catching up a little.

arctic forum
main tinsel
#

!e py from ctypes import c_void_p print(type(c_void_p))

brazen tinselBOT
main tinsel
#

_CDataMeta I've no idea about this.

arctic forum
#

_SimpleCData herit of _CData which as the metaclass _CDataMeta that look like this:

class _CDataMeta(type):
    # By default mypy complains about the following two methods, because strictly speaking cls
    # might not be a Type[_CT]. However this can never actually happen, because the only class that
    # uses _CDataMeta as its metaclass is _CData. So it's safe to ignore the errors here.
    def __mul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ...  # type: ignore[misc]  # pyright: ignore[reportGeneralTypeIssues]
    def __rmul__(cls: type[_CT], other: int) -> type[Array[_CT]]: ...  # type: ignore[misc]  # pyright: ignore[reportGeneralTypeIssues]
brazen tinselBOT
#
Python help channel closed

This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.