Доступ на запись для итераторов? Или: отправка значений в генераторы numpy Arrays - PullRequest
2 голосов
/ 29 марта 2012

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

У меня есть класс, заключающий в список numpy.ndarray:

class wrapper:
    def __init__(self, myList):
        self.myList = myList

    def getArrayIterator(self):
        for arr in self.myList:
            yield arr

#set list of arrays in wrapper
myList = [rand(3,3), rand(3,3), rand(3,3)]
w = wrapper(myList)

Как я понял, второй метод возвращает генератор. Теперь я хочу использовать этот генератор для циклического перемещения по списку и сброса массивов в другое значение:

for a in w.getArrayIterator():
    a = zeros((3,4))

Я надеялся получить здесь семантику ссылок, но, похоже, это не так.

Итак, я попытался использовать Python send() в моей функции getArrayIterator:

# ...
def getArrayIterator(self):
    for arr in self.myList:
        val = (yield arr)
        if val is not None:
            arr = val
# ...

Но это тоже не сработает, потому что:

a.send(zeros((3,4)))
  AttributeError: 'numpy.ndarray' object has no attribute 'send'

Есть ли простое решение для достижения желаемого поведения? Я что-то упустил?


РЕДАКТИРОВАТЬ: Мне было указано, что я должен предоставить больше информации о моей реальной проблеме. Приведенный выше пример, конечно, упрощен.

У меня есть список списков numpy.ndarray, представляющих тензор T, инкапсулированный в моем классе. При доступе к элементу T: t_ijkl мне нужно умножить матрицы, хранящиеся в списке: A(i)*B(j)*C(k)*D(l), первый и последний - векторы строки / столбца.

Итак, в моем приложении есть набор A, набор B и т. Д. Каждый из них принадлежит точке сетки.

Теперь я хотел иметь итератор для всех точек сетки и итераторы для матриц, связанных с каждой точкой сетки.

Первой идеей, которая пришла в голову, было использование итераторов в стиле c ++ для чтения и записи матриц. Но, как указано ниже, это не совсем осуществимый подход. Поэтому я думаю, что я буду использовать разные итераторы только для доступа на чтение и специализированные методы установки для установки новых значений для матриц.

Ответы [ 3 ]

2 голосов
/ 29 марта 2012

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

Когда вы делаете

name = somelist[0]
name = 'other'

вы указываете имя name на объект по первому индексу в somelist, затем указываете имя name на объект 'other'. Ты никогда не указываешь somelist[0] на 'other'.

Таким образом, в дополнение к send вам необходимо назначить список:

class wrapper:
    def __init__(self, myList):
        self.myList = myList

    def getArrayIterator(self):
        for i, arr in enumerate(self.myList):
            yarr = (yield arr)
            if yarr is not None:
                self.myList[i] = yarr

#set list of arrays in wrapper
myList = [1, 2, 3, 4, 5]
w = wrapper(myList)
witer = w.getArrayIterator()
try:
    a = next(witer)
    for i in range(6, 11):
        print a,
        a = witer.send(i)
except StopIteration:
    pass
print
print w.myList
0 голосов
/ 29 марта 2012

Звучит так, как будто вы хотите реализовать __getitem__ и __setitem__.

class wrapper:
    def __init__(self, myList):
        self.myList = myList    

    def __iter__(self):
        for arr in self.myList:
            yield arr    

    def __getitem__(self, key):
        return self.myList[key]   

    def __setitem__(self, key, value):
        self.myList[key] = value

Использование:

for index, arr in enumerate(w):
    same_arr = w[index]
    w[index] = zeros((3,4))

Существует множество других полезных функций, которые вы можете реализовать, если считаете, что это облегчит вашу жизнь. Вот документация об эмуляции типов контейнеров.

0 голосов
/ 29 марта 2012

Вы можете только читать значение, используя генератор (ключевое слово yield), не записывая его

...