There are some edges in ctypes where you may be expect something
else than what actually happens.
Consider the following example:
>>> from ctypes import *
>>> class POINT(Structure):
... _fields_ = ("x", c_int), ("y", c_int)
...
>>> class RECT(Structure):
... _fields_ = ("a", POINT), ("b", POINT)
...
>>> p1 = POINT(1, 2)
>>> p2 = POINT(3, 4)
>>> rc = RECT(p1, p2)
>>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y
1 2 3 4
>>> # now swap the two points
>>> rc.a, rc.b = rc.b, rc.a
>>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y
3 4 3 4
>>>
Hm. We certainly expected the last statement to print 3 4 1 2.
What happended? Here are the steps of the rc.a, rc.b = rc.b, rc.a
line above:
>>> temp0, temp1 = rc.b, rc.a >>> rc.a = temp0 >>> rc.b = temp1 >>>
Note that temp0 and temp1 are objects still using the internal
buffer of the rc object above. So executing rc.a = temp0
copies the buffer contents of temp0 into rc 's buffer. This,
in turn, changes the contents of temp1. So, the last assignment
rc.b = temp1, doesn't have the expected effect.
Keep in mind that retrieving subobjects from Structure, Unions, and Arrays doesn't copy the subobject, instead it retrieves a wrapper object accessing the root-object's underlying buffer.
Another example that may behave different from what one would expect is this:
>>> s = c_char_p() >>> s.value = "abc def ghi" >>> s.value 'abc def ghi' >>> s.value is s.value False >>>
Why is it printing False? ctypes instances are objects containing
a memory block plus some descriptors accessing the contents of the
memory. Storing a Python object in the memory block does not store
the object itself, instead the contents of the object is stored.
Accessing the contents again constructs a new Python each time!
See About this document... for information on suggesting changes.