Как создать подкласс numpy.ndarray - PullRequest
6 голосов
/ 08 сентября 2011

Я изо всех сил пытаюсь создать подкласс моего собственного подкласса numpy.ndarray.Я не очень понимаю, в чем проблема, и хотел бы, чтобы кто-то объяснил, что идет не так в следующих случаях и как сделать то, что я пытаюсь сделать.

Чего я пытаюсь достичь:

У меня есть подкласс numpy.ndarry, который ведет себя так, как я хочу (класс A в коде ниже).Я хочу создать подкласс A (класс B в приведенном ниже коде), чтобы B содержал дополнительную информацию (имя) и методы (украшенный метод .simple_data).

Случай 1:

import numpy as np

class A(np.ndarray):

    def __new__(cls,data):
        obj = np.asarray(data).view(cls)
        return obj

    def __array_finalize(self,obj):
        if obj is None: return

class B(A):

    def __init__(self,data,name):
        super(B,self).__init__(data)
        self.name = name

    @property
    def simple_data(self):
        return [data[0,:],data[:,0]]

if __name__ == '__main__':
    data = np.arange(20).reshape((4,5))
    b = B(data,'B')
    print type(b)
    print b.simple_data

Запуск этого кода приводит к выводу:

Traceback (most recent call last):
  File "ndsubclass.py", line 24, in <module>
    b = B(data,'B')
TypeError: __new__() takes exactly 2 arguments (3 given)

Я предполагаю, что это связано с переменной 'name' в конструкции B и что из-за того, что A является подклассом numpy.array, A's новый метод вызывается перед B init методом.Таким образом, чтобы исправить это, я предполагаю, что B также нужен метод new , который соответствующим образом обрабатывает дополнительный аргумент.

Я думаю, что-то вроде:

def __new__(cls,data,name):
    obj = A(data)
    obj.name = name
    return obj

должен это сделать, но как мне изменить класс obj?

Случай 2:

import numpy as np

class A(np.ndarray):

    def __new__(cls,data):
        obj = np.asarray(data).view(cls)
        return obj

    def __array_finalize__(self,obj):
        if obj is None: return

class B(A):

    def __new__(cls,data):
        obj = A(data)
        obj.view(cls)
        return obj

    def __array_finalize__(self,obj):
        if obj is None: return

    @property
    def simple_data(self):
        return [self[0,:],self[:,0]]

if __name__ == '__main__':
    data = np.arange(20).reshape((4,5))
    b = B(data)
    print type(b)
    print b.simple_data()

При запуске вывод:

<class '__main__.A'>
Traceback (most recent call last):
  File "ndsubclass.py", line 30, in <module>
    print b.simple_data()
AttributeError: 'A' object has no attribute 'simple_data'

Это удивляет меня, как я и ожидал:

<class '__main__.B'>
[array([0, 1, 2, 3, 4]), array([ 0,  5, 10, 15])]

Я предполагаю, что вызов view () в B. new () как-то не правильно устанавливает класс obj.Почему?

Я не понимаю, что происходит, и был бы очень признателен, если бы кто-то смог это объяснить.

1 Ответ

4 голосов
/ 08 сентября 2011

Для Случай 1 , самый простой способ:

class B(A):
    def __new__(cls,data,name):
        obj = A.__new__(cls, data)
        obj.name = name
        return obj

__new__ на самом деле является статическим методом, который принимает класс в качестве первого аргумента, а не метод класса, поэтомуВы можете вызвать его напрямую с классом, для которого вы хотите создать экземпляр.

Для Case 2 , view не работает на месте, вам нужно присвоить результатк чему-то, самый простой способ:

class B(A):
    def __new__(cls,data):
        obj = A(data)
        return obj.view(cls)

Кроме того, вы __array_finalize__ определили то же самое в A и B там (вероятно, просто опечатка) - вы не делаетенужно сделать это.

...