3

我想在每次设置 numpy 数组时对其内容进行检查。可以为此使用python属性吗?我的做法:

import numpy as np

class Obj(): 
    def __init__(self):                                                                                 
        self._np_arr = None                                                                             

    @property                                                                                           
    def np_arr(self):                                                                                   
        if self._np_arr is None:                                                                        
            self._np_arr = np.ones(10)                                                                  
        return self._np_arr                                                                             

    @np_arr.setter
    def np_arr(self, value):
        if np.sum(value)>10:
            raise ValueError('Error message')                                                           
        self._np_arr = value

if __name__ == '__main__':
    o = Obj()                                                                                           
    print o.np_arr
    o.np_arr = np.zeros(10) # ok                                                                        
    o.np_arr = np.ones(10)*2 # not ok                                                                   
    print o.np_arr       

当对象仍然是 None 时输入 getter。一旦 np_arr 是一个 numpy 数组,getter 和 setter 就不再起作用。

我究竟做错了什么?

4

3 回答 3

3

属性仅适用于新型类 - 更改class Obj():class Obj(object):提供预期输出:

$ python2 test.py
[ 1.  1.  1.  1.  1.  1.  1.  1.  1.  1.]
Traceback (most recent call last):
  File "test.py", line 22, in <module>
    o.np_arr = np.ones(10) * 2
  File "test.py", line 16, in np_arr
    raise ValueError('Error message')
ValueError: Error message

WhenObj是一个老式的类(Python 2 中的默认值),分配 too.np_arr不会调用 setter - 它的行为就像一个常规的属性分配,并且破坏了属性。

于 2012-09-19T09:33:24.387 回答
3

首先。这很难(最多,我相信不可能)做对。这里的错误很简单,一定是新的样式类。所以只需替换class Obj()class Obj(object).

但是,这可能无法解决您的问题,因为用户仍然可以将其分配到位,即:

o.np_arr[:] = 2

您可以通过使用来规避这一点_np_arr.setflags(write=False),但是用户根本无法使用此类操作。

编辑:你也可以继承ndarray,并定义你自己的__array_finalize__来规避它。但是,即使那样,用户也可以np.asarray(o.np_arr)就地执行和修改...

我想您可以提供自己的方法,然后通过在可写的内部工作来“模拟”一个数组。但我怀疑是否有 100% 万无一失或至少优雅的方法。

于 2012-09-19T09:38:14.143 回答
0

使用“_”前缀表示它是私有的,同时还定义 get/set 属性以直接将其访问为 o._np_arr.

如果您希望它真正私有,也许您宁愿定义明确的 get/setter ( o.set_arr, o.get_arr) 并邀请用户不要就地修改它。

于 2012-09-19T12:09:44.610 回答