numpy.ndarray: преобразование в «нормальный» класс - PullRequest
6 голосов
/ 21 января 2011

[Python 3]

Мне нравится ndarray, но я нахожу это раздражающим в использовании.

Вот одна проблема, с которой я сталкиваюсь.Я хочу написать class Array, который унаследует большую часть функциональности ndarray, но будет иметь только один способ создания экземпляров: массив с нулевым заполнением определенного размера.Я надеялся написать:

class Array(numpy.ndarray):
  def __init__(size):
    # What do here?

Я хотел бы вызвать super().__init__ с некоторыми параметрами, чтобы создать заполненный нулями массив, но он не будет работать, поскольку ndarray использует глобальную функцию numpy.zeros (а не конструктор) для создания массива, заполненного нулями.

Вопросы:

  1. Почему ndarray во многих случаях использует глобальные (модульные) функции вместо конструкторовслучаи?Это большое раздражение, если я пытаюсь использовать их в объектно-ориентированной среде.

  2. Какой лучший способ определить class Array, который мне нужен?Стоит ли просто вручную заполнять ndarray нулями, или есть ли способ повторно использовать функцию zeros?

Ответы [ 3 ]

7 голосов
/ 21 января 2011

Почему ndarray во многих случаях использует глобальные (модульные) функции вместо конструкторов?

  1. Чтобы быть совместимым / похожим на Matlab, где изначально были созданы такие функции как zeros или ones
  2. Глобальные заводские функции быстро пишутся и просты для понимания. Какой должна быть семантика конструктора, например, Как бы вы выразили простой zeros или empty или ones с одним конструктором? На самом деле, такие фабричные функции довольно распространены, в том числе и в других языках программирования.

Какой лучший способ определить class Array, что мне нужно?

import numpy

class Array(numpy.ndarray):
    def __new__(cls, size):
        result = numpy.ndarray.__new__(Array, size)
        result.fill(0)
        return result
arr = Array(5)

def test(a):
    print type(a), a

test(arr)
test(arr[2:4])
test(arr.view(int))

arr[2:4] = 5.5

test(arr)
test(arr[2:4])
test(arr.view(int))

Обратите внимание, что это Python 2, но для работы с Python 3 потребуются лишь небольшие изменения.

6 голосов
/ 21 января 2011

Если вам не нравится ndarray интерфейс, не наследуйте его. Вы можете определить свой собственный интерфейс и делегировать остальное ndarray и numpy.

import functools
import numpy as np


class Array(object):

    def __init__(self, size):
        self._array = np.zeros(size)

    def __getattr__(self, attr):
        try: return getattr(self._array, attr)
        except AttributeError:
            # extend interface to all functions from numpy
            f = getattr(np, attr, None)
            if hasattr(f, '__call__'):
                return functools.partial(f, self._array)
            else:
                raise AttributeError(attr)

    def allzero(self):
        return np.allclose(self._array, 0)


a = Array(10)
# ndarray doesn't have 'sometrue()' that is the same as 'any()' that it has.
assert a.sometrue() == a.any() == False
assert a.allzero()

try: a.non_existent
except AttributeError:
    pass
else:
    assert 0
4 голосов
/ 22 января 2011

Наследование ndarray немного сложнее. ndarray даже не имеет метода __init(self, )___, поэтому его нельзя вызвать из подкласса, но для этого есть причины. Пожалуйста, смотрите документацию о подклассах .

Кстати, не могли бы вы рассказать о своих конкретных потребностях? Все еще довольно легко приготовить класс (используя ndarray) для своих собственных нужд, но подкласс ndarray для прохождения всего этого тупого механизма - это совсем другая проблема.

Кажется, я не могу комментировать свой пост, нечетно
@Philipp: Он будет вызываться Python, но не numpy. Существует три способа создания ndarray, и в этом документе приведены рекомендации по работе со всеми делами.

...