Numpy переназначение переменной не работает - PullRequest
1 голос
/ 07 апреля 2020

Я пытаюсь найти переменные, которые не являются массивом Numpy, и изменить их на массив следующим образом:

import numpy as np
a = 1
b = np.array([1,2,3])
c = np.array([1,2,3])

for item in a, b, c:
        if type(item) != np.ndarray:
            print(item)
            item *= np.ones(3)
            print(item)

Результат второго print показывает, что переменная a изменяется на массив [1. 1. 1.], но когда я проверяю ее, она все равно a=1. Почему? Как я могу решить эту проблему?

Ответы [ 3 ]

2 голосов
/ 07 апреля 2020

Когда вы пишете a = 1, имя a связывается с объектом python int. Python int s являются неизменными. Результатом любой операции над ним является всегда другого объекта.

Вопреки тому, что подразумевают другие ответы, item is a равно True для первой итерации l oop : оба имени привязаны к одному и тому же объекту int. Проблема с линией item *= np.ones(3). Помните, что операция возвращает новый массив numpy. Затем массив связывается с именем item независимо от того, была ли исходная привязка изменчивой или нет. Он не перепривязывает имя a, потому что вы никогда его не указывали, поэтому a по-прежнему ссылается на оригинальный 1.

Самый pythoni c способ изменить значения переменных с произвольно названными переменными. это поместить их в dict:

myvars = {
    'a': 1,
    'b': np.array([1,2,3]),
    'c': np.array([1,2,3]),
}
for name in myvars:
    ...
    myvars[name] *= np.ones(3)
    ...

Это работает, потому что строка myvars[name] *= np.ones(3) приблизительно эквивалентна

myvars[name] = operator.__imul__(myvars[name], np.ones(3))

Обратите внимание, что переназначение происходит в правильном месте независимо от того, или __imul__ возвращает новый объект, например для int, или выполняет истинную операцию на месте, как для np.ndarray.

1 голос
/ 08 апреля 2020

Я думаю, вы найдете atleast_1d поучительным. Сначала его код:

def atleast_1d(*arys):
    res = []
    for ary in arys:
        ary = asanyarray(ary)
        if ary.ndim == 0:
            result = ary.reshape(1)
        else:
            result = ary
        res.append(result)
    if len(res) == 1:
        return res[0]
    else:
        return res

С вашими образцами:

In [11]: a = 1 
    ...: b = np.array([1,2,3]) 
    ...: c = np.array([1,2,3])                                                                 

Возвращает список массивов, по одному для каждого из входов:

In [12]: np.atleast_1d(a,b,c)                                                                  
Out[12]: [array([1]), array([1, 2, 3]), array([1, 2, 3])]

распаковка затем можно использовать для переназначения переменных:

In [13]: a,b,c = np.atleast_1d(a,b,c)                                                          
In [14]: a                                                                                     
Out[14]: array([1])

Поскольку он использует asanyarray, массивы b и c не копируются (даже представления).

It не совсем то, что вы хотите, массив ones того же размера, что и b или c, но его можно адаптировать для этого.

0 голосов
/ 07 апреля 2020

Переменная for l oop item сохраняет значение a во время первой итерации l oop. Затем, при изменении item, a не обновляется, поскольку item сохраняет только значение a, а не ссылку на него. Другими словами, a и item хранят одно и то же значение, но в разных местах памяти.

Перед началом итерации я бы сохранил переменные в списке и сделал бы следующее:

import numpy as np
a=1
b = np.array([1,2,3])
c = np.array([1,2,3])
L = [a, b, c]
for i in range(len(L)):
    if type(L[i]) != np.ndarray:
        print(L[i])
        L[i] *= np.ones(3)
        print(L[i])
print(L)

При печати L все элементы должны быть массивами numpy. Это происходит потому, что внутри for l oop он обращается к элементам, которые находятся внутри списка, через ссылку по индексу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...