Понимание значений по умолчанию в подклассах `np.ndarray` - PullRequest
0 голосов
/ 20 декабря 2018

Я работаю с документацией numpy по подклассам ndarray, но наблюдаю несколько иной результат, чем описанный, в отношении установки значений по умолчанию.Похоже, что в документе указано, что для установки значения по умолчанию для дополнительного атрибута следует использовать одно местоположение, но я считаю, что необходимо поддерживать правильное значение по умолчанию в двух местах.

Рассмотрим реалистичный пример описанный в документе, воспроизведенный здесь (комментарии были переформатированы для краткости):

import numpy as np

class RealisticInfoArray(np.ndarray):

    def __new__(cls, input_array, info=None):
        obj = np.asarray(input_array).view(cls)
        obj.info = info
        return obj

    def __array_finalize__(self, obj):
        # Note that it is here, rather than in the __new__ method,
        # that we set the default value for 'info', because this
        # method sees all creation of default objects - with the
        # InfoArray.__new__ constructor, but also with
        # arr.view(InfoArray).
        if obj is None: return
        self.info = getattr(obj, 'info', None)

Комментарий, описывающий, где значение по умолчанию вступает в силу, сбивает меня с толку.Я заменил значения по умолчанию, чтобы увидеть, что происходит: info='michelangelo' в __new__ и getattr(obj, 'info', 'donatello') в __array_finalize__.Я считаю, что последний устанавливается только с помощью метода создания view, а первый используется для явных вызовов конструктора и создания из шаблона:

>>> a = RealisticInfoArray(np.arange(10)); print(a.info)
michelangelo
>>> b = np.arange(10).view(RealisticInfoArray); print(b.info)
donatello
>>> c = a[1:]; print(c.info)
michelangelo

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

Во-первых, я допустил ошибку?И если нет, то нужно ли мне поддерживать запланированное значение по умолчанию в обоих местах или есть способ уменьшить его до одного?(Я попытался сделать это в своем ответе ниже, любая обратная связь приветствуется.)

1 Ответ

0 голосов
/ 20 декабря 2018

Мой текущий обходной путь для этого (кроме поддержания двух значений по умолчанию) заключается в предоставлении атрибута класса DEFAULT_INFO, к которому могут обращаться как __new__, так и __array_finalize__:

import numpy as np

class RealisticInfoArray(np.ndarray):

    DEFAULT_INFO = 'michelangelo'

    def __new__(cls, input_array, info=None):
        obj = np.asarray(input_array).view(cls)
        if info is None:
            info = obj.DEFAULT_INFO
        obj.info = info
        return obj

    def __array_finalize__(self, obj):
        if obj is None: return
        self.info = getattr(obj, 'info', self.DEFAULT_INFO)

который правильно выдает:

>>> a = RealisticInfoArray(np.arange(10)); print(a.info)
michelangelo
>>> b = np.arange(10).view(RealisticInfoArray); print(b.info)
michelangelo
>>> c = a[1:]; print(c.info)
michelangelo

Это также имеет дополнительное преимущество, заключающееся в том, что пользователь класса может изменять значение по умолчанию (например, RealisticInfoArray.DEFAULT_INFO = 'leonardo') и использовать свое собственное значение по умолчанию, как он считает нужным.Однако я не проверял это решение на непредвиденные побочные эффекты.

...