1

Python 3.2.2でctypesを使用して、いくつかのCデータ構造をカプセル化しています。最終的な目標は、構造体のデータコンテンツが変更されたときに、C構造体の通知をラップするオブジェクトを作成できるようにすることです。

代表的なコード:

from ctypes import *

class Comm(Structure):
    def __init__(self):
        self.attributes_updated = False

    def __setattr__(self, name, value):
        super(Comm, self).__setattr__('attributes_updated', True)
        super(Comm, self).__setattr__(name, value)


class MyCStruct(Comm):
    _fields_ = [('number', c_int),
                ('array', c_int*5)]

    def __init__(self):
        Comm.__init__(self)

これは、「数値」などの単純なデータ属性に最適です。

>>> s = MyCStruct()
>>> s.attributes_updated
False
>>> s.value = 123
>>> s.attributes_updated
True

__setattr__属性へのインデックス表記を介したアクセスに対しては呼び出されないため、 配列であるC構造体のメンバーの属性arrayをオーバーライドしたいと思います。__setitem__おそらく、その時点で、包含オブジェクトの変数を変更できるように、包含オブジェクトへの参照を含める必要がありますがattributes_updated、配列属性へのアクセスを便利な方法でトラップできるようにはなりません。単純な属性へのアクセスをトラップできること。_fields_ctypesが変数を介して作成するインデックス可能なオブジェクトでこれを行う方法はありますか?オーバーライドすることは可能__setitem__ですs.arrayか?これを行うためのより良い方法があるでしょうか?

理想的には、これは起こります:

>>> s = MyCStruct()
>>> s.attributes_updated
False
>>> s.array[2] = 456
>>> s.attributes_updated
True

フォローアップの質問のために編集します:

多次元配列はどうですか?

class MyCStruct(Comm):
    _fields_ = [('number', c_int),
                ('array', (c_int*5)*2]

私は誤って以下の答えを期待していました。これは、1次元配列で見事に機能し、任意にネストされた配列でも同じことを行います。プロキシオブジェクトを再帰的に生成して、複数の次元を持つ配列に対して同じことを行う方法があるはずです、そうですか?構文は私を逃れます。

4

1 に答える 1

1

良い解決策は、配列の代わりにプロキシオブジェクトを返すことです。これにより、配列へのアクセスを処理できます。このようなものである可能性があります:

from ctypes import *

class ArrayProxy(object):
    def __init__(self, array, struct):
        self.array = array
        self.struct = struct

    def __setitem__(self, i, val):
        self.array[i] = val
        self.struct.attributes_updated = True

    def __getitem__(self, i):
        item = self.array[i]
        if issubclass(type(item), Array):
            # handle multidimensional arrays
            return ArrayProxy(item, self.struct)
        return item

class Comm(Structure):
    def __init__(self):
        self.attributes_updated = False

    def __setattr__(self, name, value):
        super(Comm, self).__setattr__('attributes_updated', True)
        super(Comm, self).__setattr__(name, value)

    def __getattribute__(self, name):
        attr = super(Comm, self).__getattribute__(name)
        if issubclass(type(attr), Array):
            return ArrayProxy(attr, self)
        return attr


class MyCStruct(Comm):
    _fields_ = [('number', c_int),
                ('array', c_int*5),
                ('multiarray', c_int*2*1),]

    def __init__(self):
        Comm.__init__(self)

s = MyCStruct()
print s.array
# <__main__.ArrayProxy object at 0x1b1f3d0> 
print s.attributes_updated
# False
s.array[0] = 1
print s.attributes_updated
# True

s2 = MyCStruct()
s2.multiarray[0][0] = 1
print s2.attributes_updated
# True
于 2012-05-23T21:39:02.097 に答える