I am experimenting with defining dataclasses for containing ctypes objects. I have defined three classes; two of which are used as attributes to the third: @dataclasses.dataclass class Point: x = ctypes.c_int(0) y = ctypes.c_int(0) @dataclasses.dataclass class Point2: x = ctypes.c_int(0) y = ctypes.c_int(0) @dataclasses.dataclass class TestObj: point1 = Point() point2 = Point() The TestObj class is then passed to a C function inc: #include <stdio.h> void inc(int *x, int *y) { *x = *x + 1; *y = *y + 1; } via a wrapper: def inc(test: TestObj): _inc = lib.inc _inc.argtypes = [ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)] _inc.restype = None _inc(test.point1.x,test.point1.y) When investigating the result of the pass to inc I observe the snippet: test = TestObj() print(f"addressof test.point1.x = {ctypes.addressof(test.point1.x)}") print(f"test.point1.x.value = {test.point1.x.value}") print(f"addressof test.point1.y = {ctypes.addressof(test.point1.y)}") print(f"test.point1.y.value = {test.point1.y.value}") print(f"addressof test.point2.x = {ctypes.addressof(test.point2.x)}") print(f"test.point2.x.value = {test.point2.x.value}") print(f"addressof test.point2.y = {ctypes.addressof(test.point2.y)}") print(f"test.point2.y.value = {test.point2.y.value}") inc(test) print("after pass to inc") print(f"addressof test.point1.x = {ctypes.addressof(test.point1.x)}") print(f"test.point1.x.value = {test.point1.x.value}") print(f"addressof test.point1.y = {ctypes.addressof(test.point1.y)}") print(f"test.point1.y.value = {test.point1.y.value}") print(f"addressof test.point2.x = {ctypes.addressof(test.point2.x)}") print(f"test.point2.x.value = {test.point2.x.value}") print(f"addressof test.point2.y = {ctypes.addressof(test.point2.y)}") print(f"test.point2.y.value = {test.point2.y.value}") results in: addressof test.point1.x = 124872721403536 test.point1.x.value = 0 addressof test.point1.y = 124872719995280 test.point1.y.value = 0 addressof test.point2.x = 124872721403536 test.point2.x.value = 0 addressof test.point2.y = 124872719995280 test.point2.y.value = 0 after pass to inc addressof test.point1.x = 124872721403536 test.point1.x.value = 1 addressof test.point1.y = 124872719995280 test.point1.y.value = 1 addressof test.point2.x = 124872721403536 test.point2.x.value = 1 addressof test.point2.y = 124872719995280 test.point2.y.value = 1 the memory locations of the subsequent x and y attributes of each Point instance share the same memory location respectively and that the x and y attributes of each Point instance attributes of the TestObj instance are incremented, instead of just the point1 attributes. If I redefine TestObj as: @dataclasses.dataclass class TestObj: point1 = Point() point2 = Point2() and again pass it to the inc wrapper I observe the intended result of: addressof test.point1.x = 133142487043728 test.point1.x.value = 0 addressof test.point1.y = 133142485635472 test.point1.y.value = 0 addressof test.point2.x = 133142485635728 test.point2.x.value = 0 addressof test.point2.y = 133142485635984 test.point2.y.value = 0 after pass to inc addressof test.point1.x = 133142487043728 test.point1.x.value = 1 addressof test.point1.y = 133142485635472 test.point1.y.value = 1 addressof test.point2.x = 133142485635728 test.point2.x.value = 0 addressof test.point2.y = 133142485635984 test.point2.y.value = 0 While the x and y attributes of point1 and point2 share the same memory locations repspectively, now only the point1 x and y are incremented as intended. I am puzzled as to how this is happening, given that in both scenarios the x and y attributes seemingly share the same memory location, but the change in name of the Point attribute provides the intended result. I appreciate any and all help in understanding what is happening. Continue reading...