魔术方法__repr__与__new__方法导致AttributeError

时间:2019-01-11 11:34:51

标签: python-2.7 class methods superclass

我的目标是给numpy.ndarray一个不同的表示形式,因为我想用单位表示一些数组。因此,我编写了一个从numpy.ndarray继承其属性/方法的类。对于另一种表示形式,我想使用__repr__魔术方法,例如:

class Quantitiy(np.ndarray):
    def __new__(cls, value, unit=None, dtype=None, copy=True, order=None, subok=False, ndmin=0):

        value = np.asarray(value)

        obj = np.array(value, dtype=dtype, copy=copy, order=order, 
                       subok=True, ndmin=ndmin).view(cls)

        obj.__unit = util.def_unit(unit)
        obj.__value = value

        return obj

    def __repr__(self):
        prefix = '<{0} '.format(self.__class__.__name__)
        sep = ','
        arrstr = np.array2string(self.view(np.ndarray), 
                                 separator=sep,
                                 prefix=prefix)

        return '{0}{1} {2}>'.format(prefix, arrstr, self.__unit)

到目前为止,这很好。但是,如果我想从numpy.ndarray访问继承的方法,则会得到AttributeError,因为__repr__无法解析self.__unit

我尝试使用定义变量self.__unit并在__new__方法中调用它的私有方法解决此问题,但没有成功:

class Quantitiy(np.ndarray):
    def __new__(cls, value, unit=None, dtype=None, copy=True, order=None, subok=False, ndmin=0):

        value = np.asarray(value)

        obj = np.array(value, dtype=dtype, copy=copy, order=order, subok=True, ndmin=ndmin).view(cls)

        # Here I call the private method to initialize self.__unit.
        obj.__set_unit()
        obj.__value = value

        return obj

    def __repr__(self):
        prefix = '<{0} '.format(self.__class__.__name__)
        sep = ','
        arrstr = np.array2string(self.view(np.ndarray), separator=sep, prefix=prefix)

        return '{0}{1} {2}>'.format(prefix, arrstr, self.__unit)

    # New defined private class.
    def __set_unit(self, unit):
        self.__unit = util.def_unit(unit)

我无法使用cls.__unit = util.def_unit(unit)方法中的__new__之类的方法来解决此问题。我已经尝试在__init__之后定义一个__new__方法。此外,我试图将私有方法与公共方法互换。

我期望的是

>>> array = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
>>> q = Quantity(value, unit="meter / second")
>>> q
    <Quantitiy [[1,2,3,4],
                [5,6,7,8]] meter/second>
>>> q * q
>>> <Quantitiy [[ 1, 4, 9,16],
                [25,36,49,64]] meter**2/second**2>

>>> q.min()
>>> <Quantitiy 1 meter/second>

实际结果是:

>>> array = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
>>> q = Quantity(value, unit="meter / second")
>>> q
    <Quantitiy [[1,2,3,4],
                [5,6,7,8]] meter/second>
>>> q * q
>>> <Quantitiy [[ 1, 4, 9,16],
                [25,36,49,64]] meter**2/second**2>

# Up to here everything works fine.

>>> q.min()
>>> AttributeError: 'Quantitiy' object has no attribute 
    '_Quantitiy__unit'

有人看到错误并且可以帮助我吗?

1 个答案:

答案 0 :(得分:1)

好吧,答案是-像往常一样-in the FineManual(可以在搜索“子类化numpy ndarray”时找到-这是我实际发现的方式),并且需要实现import numpy as np class Quantitiy(np.ndarray): def __new__(cls, value, unit=None, dtype=None, copy=True, order=None, subok=False, ndmin=0): value = np.asarray(value) x = np.array(value, dtype=dtype, copy=copy, order=order, subok=True, ndmin=ndmin) obj = x.view(type=cls) obj._unit = unit obj._value = value return obj def __repr__(self): print("repr %s" % type(self)) prefix = '<{0} '.format(self.__class__.__name__) sep = ',' arrstr = np.array2string(self.view(np.ndarray), separator=sep, prefix=prefix) return '{0}{1} {2}>'.format(prefix, arrstr, self._unit) def __array_finalize__(self, obj): # see InfoArray.__array_finalize__ for comments if obj is None: return self._unit = getattr(obj, '_unit', None) self._value = getattr(obj, '_value', None)

{{1}}