-1

I create a class for an image buffer. The class looks like this:

import ctypes

class ImgBuf():
    def __init__(self, bufnr=ctypes.c_int(-1)):
        self.bufnr = bufnr

The attribute 'bufnr' is handed over to a shared library by reference and changed for buffer management. I want to have multiple instances of this class (to manage several image buffers). In the small example

import imgBuf.ImgBuf
buf1 = dicamsdk.ImgBuf()
buf2 = dicamsdk.ImgBuf()
sharedDLL.allocateBuffer(buf1)

the bufNr has been changed in the both instances. How can I make instances independent?

smiddy84
  • 285
  • 1
  • 4
  • 13
  • When I try to run that, I get `TypeError: an integer is required (got type c_int)` on the `ctypes.c_int(bufnr)` call. Are you sure this is what you actually ran? – user2357112 Dec 14 '17 at 18:31
  • Indeed there was a type due to from reduction of the code. Corrected that. Thanks. – smiddy84 Dec 15 '17 at 09:56

3 Answers3

2

ctypes.c_int, like list, is mutable, which should not use as a default argument, a very common mistake. You should create a new object each time the function is called:

class ImgBuf():
    def __init__(self, bufnr=None):
        if bufnr is None:
            bufnr = ctypes.c_int(-1)
        self.bufnr =ctypes.c_int(bufnr)
georgexsh
  • 15,984
  • 2
  • 37
  • 62
1

Default values for kwargs like bufnr will only get evaluated once at load-time, when the def statement is read. So in this case, a c_int will be created once and the same instance is then used for all ImgBuf instances that don't specify bufnr explicitly.

To avoid this, you would tyipcally use None as the default, then check for is None and instantiate the default value if needed inside the function's body, which creates a new instance every time.

The same applies for any other mutable object used as a default value, like lists, dicts and so on. See this link.

Jeronimo
  • 2,268
  • 2
  • 13
  • 28
-1

See the following code snipped:

from imgBuf import ImgBuf
buf1 = ImgBuf()
buf2 = ImgBuf()
print('id(buf1) == id(buf2): ', id(buf1) == id(buf2))
print('id(buf1.bufnr) == id(buf2.bufnr): ', id(buf1.bufnr) == id(buf2.bufnr))

The output is

id(buf1) == id(buf2):  False
id(buf1.bufnr) == id(buf2.bufnr):  True

Even though python correctly creates two instances of the class object, the ctypes values have the same identity. Usually, this is not a problem as python manages the storage. But this does not apply to the shared library in use.

The default values have been copied to ensure independent instances. The class looks like this:

import ctypes
from copy import copy

class ImgBuf():
    def __init__(self, bufnr=ctypes.c_int(-1)):
        self.bufnr = copy(ctypes.c_int(bufnr))

Now the objects should be independent (run code snipped again).

smiddy84
  • 285
  • 1
  • 4
  • 13