【问题标题】:How to implement an array-like property wrapper in python?如何在 python 中实现类似数组的属性包装器?
【发布时间】:2013-06-03 08:53:40
【问题描述】:

我在 python 中有一个类,它充当 c 库的前端。该库执行模拟并处理非常大的数据数组。这个库传递一个ctype 数组,我的包装器将它转换成一个正确的numpy.ndarray

class SomeClass(object):
    @property
    def arr(self):
        return numpy.array(self._lib.get_arr())

但是,为了确保不会发生内存问题,我将 ndarray 数据与库数据分开,因此更改 ndarray 不会导致库正在使用的真实数组发生变化。但是,我可以传递一个相同形状的新数组并覆盖库中保存的数组。

@arr.setter
def arr(self, new_arr):
    self._lib.set_arr(new_arr.ctypes)

所以,我可以像这样与数组交互:

x = SomeClass()
a = x.arr
a[0] += 1
x.arr = a

我的愿望是通过允许语法简单地为x.arr[0] += 1 来进一步简化这一点,这将更具可读性并且具有更少的变量。我不确定如何创建这样一个包装器(我几乎没有制作包装器类/函数的经验),它模仿属性但允许项目访问作为我的示例。

我将如何制作这样一个包装类?有没有更好的方法来实现这个目标?如果您有任何可以帮助的建议或阅读材料,我将不胜感激。

【问题讨论】:

    标签: python wrapper ctypes


    【解决方案1】:

    这可以工作。 Array 是 Numpy/C 数组的代理:

    class Array(object):
    
        def __init__(self):
            #self.__lib = ...
            self.np_array = numpy.array(self._lib.get_arr())
    
        def __getitem__(self, key): 
            self.np_array = numpy.array(self._lib.get_arr())
            return self.np_array.__getitem__(key)
    
        def __setitem__(self, key, value):
            self.np_array.__setitem__(key, value)
            self._lib.set_arr(new_arr.ctypes)
    
        def __getattr__(self, name):
            """Delegate to NumPy array."""
            try:
                return getattr(self.np_array, name)
            except AttributeError:
                raise AttributeError(
                     "'Array' object has no attribute {}".format(name))
    

    应该是这样的:

    >>> a = Array()
    >>> a[1]
    1
    >>> a[1] = 10
    >>> a[1]
    10
    

    10 也应该在你的 C 数组中结束。

    【讨论】:

    • 是的,我认为这样的事情最终可能会奏效。我试图创建一个这样的类,但这种方法的问题是你失去了拥有 ndarray 的所有好处。例如,a.shape 将失败,因为您确实需要 a.np_array.shape。我试图从numpy.ndarray 继承,但我的尝试失败了。你知道怎么可能做到这一点吗?
    • 添加了一些委托代码。现在a.shape 应该给a.np_array.shape
    • 当然,重定向__getattr__ 正是我应该做的¥。非常感谢您的想法!
    • 只是最后一两点,重载__str____repr__ 可能仍然很重要。另外,由于我们基本上使用了ndarray 的所有属性,所以让numpy 引发异常而不是Array 会更好吗?
    • 当然,这只是一个非常基本的例子。您可以根据需要添加更多特殊方法,例如__str____repr__,也许首先是一个非常具有描述性的文档字符串。您可以拦截np 数组引发的异常,并在重新引发它们之前添加更多信息。如果这让事情变得更容易理解,那就去做吧,如果不使用普通的 NumPy 异常。
    【解决方案2】:

    我认为您的描述符应该返回了解self._lib 的类列表类的实例,并将在正常操作期间更新它append__setitem____getitem__ 等。

    【讨论】:

    • 我认为你是对的,它需要是一个像 Muler 的想法一样返回一个包装数组的包装器,但增加了正在使用的任何库的知识。感谢您的建议。
    • 好吧 __setitem__ 更新 NumPy 数组和 C _lib。 NumPy 数组不支持append,因为有固定大小。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    相关资源
    最近更新 更多