Friday, August 5, 2011

Exploring ctypes (5)

I was a little snarky about how the ctypes docs start with all Windows examples, but once you get to here they are really excellent. So I won't say too much more about them except to reproduce a fun example:


>>> from ctypes import *
>>> class cell(Structure):
...     pass
... 
>>> cell._fields_ = [('name', c_char_p),
...                  ('next', POINTER(cell))]
>>> 
>>> c1 = cell()
>>> c1.name = 'foo'
>>> c2 = cell()
>>> c2.name = 'bar'
>>> c1.next = pointer(c2)
>>> c2.next = pointer(c1)
>>> p = c1
>>> for i in range(8):
...     print p.name,
...     p = p.next[0]
... 
foo bar foo bar foo bar foo bar

This linked list is a classic example of something that needs a "forward declaration" of the cell type in C.

One other small point, from the docs:
Either the LoadLibrary() method of the dll loaders should be used, or you should load the library by creating an instance of CDLL by calling the constructor:

We used the second method before. To use the first with the example from the other day (here):

>>> import ctypes
>>> libadd = ctypes.cdll.LoadLibrary('add1.so')
>>> libadd.f1(2)
3
>>> libadd.f1(2,3)
3
>>> libadd.f1()
1858614497
>>> libadd.f1.argtypes = [ctypes.c_int]
>>> libadd.f1(2,3)
3
>>> libadd.f1()
Traceback (most recent call last):
File "", line 1, in 
TypeError: this function takes at least 1 argument (0 given)
>>> 

You can get some error checking with the argtypes call, but not everything.

A developer of Cython gave a nice summary of why you might want to start with that in the SO post cited the other day. But for my small purposes, I think ctypes will probably be everything I'll need.