使用另一个生成器的生成器理解
Generator comprehension using another generator
我正在尝试编写一个 returns 和 Generator
的方法。这两种方法的最终结果是得到以下形式的两个列表的组合:'A #1', 'B #1', ..., 'F #9'
FLATS = ['A', 'B', 'C', 'D', 'E', 'F']
def generate_nums() -> Generator[str, None, None]:
prefix = '#'
for num in range(10):
code = ''.join([prefix, str(num)])
yield code
def generate_room_numbers() -> Generator[str, None, None]:
room_nums = generate_nums()
yield (' '.join([flat_name, room_num]) for room_num in room_nums for flat_name in FLATS)
if __name__ == "__main__":
result = generate_room_numbers()
result = next(result) # I hate this. How do I get rid of this?
for room in result:
print(room)
这给了我正确的结果。虽然,我的烦恼是 result = next(result)
行。有一个更好的方法吗?我查看了 this 答案以及 yield from
语法,但我几乎不能完全理解生成器。
您可以使用生成器表达式和 f 字符串:
FLATS = ['A', 'B', 'C', 'D', 'E', 'F']
room_numbers = (f'{letter} #{i}' for i in range(1, 10) for letter in FLATS)
for room in room_numbers:
print(room)
输出:
A #1
B #1
C #1
.
.
.
D #9
E #9
F #9
最好将 yield
语句放在显式循环中,而不是试图生成生成器。
您的 generate_room_numbers
应如下所示:
def generate_room_numbers():
for flat_name in FLATS:
room_nums = generate_nums()
for room_num in room_nums:
yield (' '.join([flat_name, room_num]))
请注意 generate_nums()
在 循环 中被调用,因为您不能重复迭代它 returns 的同一个迭代器;在遍历它之后,它被耗尽并且 generate_nums
每次都会提高 StopIteration
(这样迭代会产生一个空序列)。
(如果 generate_nums
很昂贵,那么您当然可以在 flat_name
循环之外执行 nums = list(generate_nums())
然后在循环内迭代它,但是如果这可能需要大量内存,然后它可能会破坏首先使用生成器的大部分意义。)
除主代码中的 result = next(result)
被删除外,您的其余代码没有变化,但为了方便起见,这里是整个代码:
FLATS = ['A', 'B', 'C', 'D', 'E', 'F']
def generate_nums():
prefix = '#'
for num in range(10):
code = ''.join([prefix, str(num)])
yield code
def generate_room_numbers():
for flat_name in FLATS:
room_nums = generate_nums()
for room_num in room_nums:
yield (' '.join([flat_name, room_num]))
if __name__ == "__main__":
result = generate_room_numbers()
# result = next(result) <<==== NOT NEEDED ANY MORE
for room in result:
print(room)
我正在尝试编写一个 returns 和 Generator
的方法。这两种方法的最终结果是得到以下形式的两个列表的组合:'A #1', 'B #1', ..., 'F #9'
FLATS = ['A', 'B', 'C', 'D', 'E', 'F']
def generate_nums() -> Generator[str, None, None]:
prefix = '#'
for num in range(10):
code = ''.join([prefix, str(num)])
yield code
def generate_room_numbers() -> Generator[str, None, None]:
room_nums = generate_nums()
yield (' '.join([flat_name, room_num]) for room_num in room_nums for flat_name in FLATS)
if __name__ == "__main__":
result = generate_room_numbers()
result = next(result) # I hate this. How do I get rid of this?
for room in result:
print(room)
这给了我正确的结果。虽然,我的烦恼是 result = next(result)
行。有一个更好的方法吗?我查看了 this 答案以及 yield from
语法,但我几乎不能完全理解生成器。
您可以使用生成器表达式和 f 字符串:
FLATS = ['A', 'B', 'C', 'D', 'E', 'F']
room_numbers = (f'{letter} #{i}' for i in range(1, 10) for letter in FLATS)
for room in room_numbers:
print(room)
输出:
A #1
B #1
C #1
.
.
.
D #9
E #9
F #9
最好将 yield
语句放在显式循环中,而不是试图生成生成器。
您的 generate_room_numbers
应如下所示:
def generate_room_numbers():
for flat_name in FLATS:
room_nums = generate_nums()
for room_num in room_nums:
yield (' '.join([flat_name, room_num]))
请注意 generate_nums()
在 循环 中被调用,因为您不能重复迭代它 returns 的同一个迭代器;在遍历它之后,它被耗尽并且 generate_nums
每次都会提高 StopIteration
(这样迭代会产生一个空序列)。
(如果 generate_nums
很昂贵,那么您当然可以在 flat_name
循环之外执行 nums = list(generate_nums())
然后在循环内迭代它,但是如果这可能需要大量内存,然后它可能会破坏首先使用生成器的大部分意义。)
除主代码中的 result = next(result)
被删除外,您的其余代码没有变化,但为了方便起见,这里是整个代码:
FLATS = ['A', 'B', 'C', 'D', 'E', 'F']
def generate_nums():
prefix = '#'
for num in range(10):
code = ''.join([prefix, str(num)])
yield code
def generate_room_numbers():
for flat_name in FLATS:
room_nums = generate_nums()
for room_num in room_nums:
yield (' '.join([flat_name, room_num]))
if __name__ == "__main__":
result = generate_room_numbers()
# result = next(result) <<==== NOT NEEDED ANY MORE
for room in result:
print(room)