Как создать вложенные структуры генератора в Python?
Я пытаюсь создать ImageSeries
объект, где я хочу получить изображения по определенному шаблону (для каждого значения в xy и каждого значения в z), и я вызываю методы, которые добавят генератор в список задач, и запускаю генератор через два цикла for, чтобы выполнить этот.
Но моя вторая задача исчерпывается после первой итерации первой задачи, что не является моим желаемым результатом. Я хочу, чтобы вторая задача выполнялась на каждой итерации первой задачи.
Мне было интересно, есть ли эффективные способы программирования подобных шаблонов.
class ImageSeries:
tasks = []
def xy(self, position):
print(position)
yield "xy"
def z(self, position):
print(position)
yield "z"
def xy_scan(self, positions):
self.tasks.append((self.xy(pos) for pos in positions))
def z_scan(self, positions):
self.tasks.append((self.z(pos) for pos in positions))
def run(self):
for i in self.tasks[0]:
next(i)
for j in self.tasks[1]:
next(j)
def __repr__(self):
return str(self.tasks)
if __name__ == "__main__":
s = ImageSeries()
positions = [[0, 0], [100, 100], [1000, 1000]]
s.xy_scan(positions)
s.z_scan([0, 100, 1000, 10000])
Токовый выход:
[0, 0]
0
100
1000
10000
[100, 100]
[1000, 1000]
Ожидаемый результат:
>>> s.run()
[0, 0]
0
100
1000
10000
[100, 100]
0
100
1000
10000
[1000, 1000]
0
100
1000
10000
2 ответа
Ну вот
class ImageSeries:
def __init__(self):
self._xy_tasks = None
self._z_tasks = None
def xy(self, position):
print(position)
yield "xy"
def z(self, position):
print(position)
yield "z"
def xy_scan(self, positions):
self._xy_tasks = lambda: (self.xy(pos) for pos in positions)
def z_scan(self, positions):
self._z_tasks = lambda: (self.z(pos) for pos in positions)
def run(self):
for xy_generator in self._xy_tasks():
next(xy_generator)
for z_generator in self._z_tasks():
next(z_generator)
def __repr__(self):
return str(self._xy_tasks()) + " " + str(self._z_tasks())
if __name__ == "__main__":
s = ImageSeries()
positions = [[0, 0], [100, 100], [1000, 1000]]
s.xy_scan(positions)
s.z_scan([0, 100, 1000, 10000])
s.run()
Сделал кое-что:
- называется
run()
- В качестве списка self.tasks не имеет смысла, поскольку каждая ячейка имеет разное значение, поэтому я разделил его на две отдельные переменные-члены.
- Главное было убедиться, что генератор будет создаваться заново при каждом запуске, так как его нельзя сбросить. Я добился этого с помощью лямбда, поэтому вы можете вызывать функцию, которая каждый раз создает генератор, а не сам генератор. Обратите внимание на
self._xy_tasks()
. Это вызывает функцию, которая создает генератор.
Генераторы не знают, что они вложены. После того, как в первый раз генератор был исчерпан, он закончился. Фактически, вам не нужны генераторы в этом случае, поскольку они имеют смысл, когда вы повторяете длинный список, который не хотите хранить в памяти. Но здесь все повторяющиеся последовательности нужно сохранять в памяти. Вы можете использовать генератор только на верхнем уровне цикла. Но это имеет смысл только в том случае, если оно действительно длинное и получено из какого-то ручья. Если он уже находится в памяти, вам действительно не нужны генераторы. Все, что вы хотите, можно сделать намного проще
xy_list = [[0, 0], [100, 100], [1000, 1000]]
z_list = [0, 100, 1000, 10000]
for xy in xy_list:
print(xy)
for z in z_list:
print(z)
Если вам нужен класс, просто используйте xy_scan
, z_scan
сохранить в self.xy_list
, self.z_list
и использовать то же самое for
зациклиться run
метод (просто добавьте self.
к xy_list
а также z_list
)