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.