Это правильный способ создания представления только для чтения массива numpy? - PullRequest
2 голосов
/ 23 марта 2020

Я хотел бы создать ссылку только для чтения на массив NumPy. Это правильный способ сделать b доступной только для чтения ссылкой на a (a - это любой массив NumPy)?

def get_readonly_view(a):
    b = a.view()
    b.flags.writeable = False
    return b

В частности, я хотел бы убедиться, что вышеприведенное делает не копировать содержимое a? (Я пытался проверить это с помощью np.shares_memory, и он возвращает True. Но я не уверен, является ли это правильным тестом.)

Кроме того, мне интересно, реализован ли get_readonly_view в * 1029? *?


Обновление. Было предложено превратить массив в свойство класса, чтобы сделать его доступным только для чтения. Я думаю, что это не работает:

import numpy as np

class Foo:

    def __init__(self):
        self._a = np.arange(15).reshape((3, 5))


    @property
    def a(self):
        return self._a


    def bar(self):
        print(self._a)

Но клиент может изменить содержимое _a:

>> baz = Foo()
>> baz.bar()
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]
>> baz.a[1, 2] = 10
>> baz.bar()
[[ 0  1  2  3  4]
 [ 5  6 10  8  9]
 [10 11 12 13 14]]

, в то время как я хотел бы baz.a[1, 2] = 10, чтобы вызвать исключение.

1 Ответ

1 голос
/ 23 марта 2020

Ваш подход, кажется, является предлагаемым способом создания только для чтения представления .

В частности, arr.view() (которое также можно записать как нарезка arr[:]) создаст ссылку на arr, а изменение флага writeable - это рекомендуемый способ сделать массив NumPy доступным только для чтения.

Документация также предоставляет некоторую дополнительную информацию о наследовании свойства writeable:

Область данных может быть записана в. Установка этого значения в False блокирует данные, делая их доступными только для чтения. Представление (slice, et c.) Наследует WRITEABLE от своего базового массива во время создания, но представление записываемого массива может быть впоследствии заблокировано, пока базовый массив остается доступным для записи. (Обратное неверно в том смысле, что представление заблокированного массива нельзя сделать доступным для записи. Однако в настоящее время блокировка базового объекта не блокирует любые представления, которые уже ссылаются на него, поэтому при таких обстоятельствах возможно изменить содержимое заблокированного массива через ранее созданный доступный для записи вид на него.) Попытка изменить массив без записи вызывает исключение RuntimeError.

Просто для повторения и проверки происходящего:

import numpy as np


def get_readonly_view(arr):
    result = arr.view()
    result.flags.writeable = False
    return result


a = np.zeros((2, 2))
b = get_readonly_view(a)

print(a.flags)
#   C_CONTIGUOUS : True
#   F_CONTIGUOUS : False
#   OWNDATA : True
#   WRITEABLE : True
#   ALIGNED : True
#   WRITEBACKIFCOPY : False
#   UPDATEIFCOPY : False
print(b.flags)
#   C_CONTIGUOUS : True
#   F_CONTIGUOUS : False
#   OWNDATA : False
#   WRITEABLE : False
#   ALIGNED : True
#   WRITEBACKIFCOPY : False
#   UPDATEIFCOPY : False

print(a.base)
# None
print(b.base)
# [[0. 0.]
#  [0. 0.]]

a[1, 1] = 1.0
# ...works
b[0, 0] = 1.0
# raises  ValueError: assignment destination is read-only
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...