@artem78

Почему неправильно работает цикл с генератором?

import decimal

def drange(x, y, jump):
  while x < y:
    yield float(x)
    x += decimal.Decimal(jump)

heights = range(126, 200 + 1, 1)
weights = drange(30, 140 + 0.5, 0.5)

for height in heights:
	for weight in weights:
		print(height, '-', weight)


Почему вместо ожидаемого перебора всех комбинаций роста и веса выводятся значения только для первого роста?:

126 - 30.0
126 - 30.5
126 - 31.0
......
126 - 139.0
126 - 139.5
126 - 140.0


Похоже, что после первого прогона генератор drange() не хочет запускаться снова. А если заменить его на стандартную функцию range() и написать так weights = range(30, 140 + 1, 1), то цикл выполняется правильно.

В чём тогда ошибка в drange()?
  • Вопрос задан
  • 162 просмотра
Решения вопроса 1
@artem78 Автор вопроса
Добился правильной работы переписав генератор на итератор и добавив сброс текущего значения в методе __iter__.

import decimal

class drange():
	def __init__(self, start, stop, step = 1):
		self.start = decimal.Decimal(start)
		self.stop = decimal.Decimal(stop)
		self.step = decimal.Decimal(step)
		self.value = self.start

	def __iter__(self):
		self.value = self.start      #  <-- Вот тут самое главное
		return self

	def __next__(self):
		if self.step > 0 and self.value < self.stop or self.step < 0 and self.value > self.stop:
			current = self.value
			self.value += self.step
			return current
		else:
			raise StopIteration()

	def __len__(self):
		return max(0, int((self.stop - self.start) / self.step + 1))
		
		
# Пользуемся
weights = drange(126, 127 + 0.5, '0.5')
heights = drange(150, 153 + 1, 1)

for weight in weights:
	for height in heights:
		print(height, '-', weight)


Результат:
150 - 126
151 - 126
152 - 126
153 - 126
150 - 126.5
151 - 126.5
152 - 126.5
153 - 126.5
150 - 127.0
151 - 127.0
152 - 127.0
153 - 127.0


Возможно кому-нибудь пригодится моё решение.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
fox_12
@fox_12 Куратор тега Python
Расставляю биты, управляю заряженными частицами
import decimal

def drange(x, y, jump):
  while x < y:
    yield float(x)
    x += decimal.Decimal(jump)

heights = range(126, 200 + 1, 1)

for height in heights:
  weights = drange(30, 140 + 0.5, 0.5)
  for weight in weights:
    print(height, '-', weight)


Потому что генератор отрабатывает только раз. Вам нужно пересоздавать объект генератора для нового запуска.
Ответ написан
@alex-t
Прогр. в команде rco.ru
range реализует интерфейс последовательности, т.е. это как бы создание соответствующего кортежа, только краткая запись. Можно в цикле, например, указать in heights[2:20]....

ну а генератор, он и есть генератор, там только перебор, пока не закончится (если закончится когда-нибудь).
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы