是否有一种方法可以在Python中访问同一函数内的yield ?



我目前正在尝试用内置属性代替手工计数产量:

def random_select(iterations):
count = 0
for index in range(iterations):
if random.randint(0, 9) > 4:
yield index
count += 1
assert count > 0

Something I am looking for:

def random_select(iterations):
for index in range(iterations):
if random.randint(0, 9) > 4:
yield index
assert len(self.__yield__.__results__) > 0

在Python中有类似的东西吗?

如果你经常这样做,目标是更少的代码,你不介意它变慢,你可以使用一个装饰器,将你的生成器包装在另一个之后断言给定检查的生成器中:

@assert_afterwards(list_check=lambda yielded: len(yielded) > 0)
def random_select(iterations):
for index in range(iterations):
if random.randint(0, 9) > 4:
yield index

虽然检查len > 0,你不需要跟踪所有的产出值,但只需要记录它们的计数,甚至只需要记录是否有产出:

@assert_afterwards(count_check=lambda yielded: yielded > 0)
def random_select(iterations):
for index in range(iterations):
if random.randint(0, 9) > 4:
yield index
@assert_afterwards(any_check=True)
def random_select(iterations):
for index in range(iterations):
if random.randint(0, 9) > 4:
yield index

该装饰器的可能实现可以通过更好的消息来改进失败的断言和至少"任意";版本可以做得更快),包括demo:

import random
random.seed(0)
def assert_afterwards(any_check=None, count_check=None, list_check=None):
def deco(gen):
if any_check:
def gen_any(*args):
yielded = False
for value in gen(*args):
yield value
yielded = True
assert yielded
return gen_any
if count_check:
def gen_count(*args):
yielded = 0
for value in gen(*args):
yield value
yielded += 1
assert count_check(yielded)
return gen_count
def gen_list(*args):
yielded = []
for value in gen(*args):
yield value
yielded.append(value)
assert list_check(yielded)
return gen_list
return deco
#@assert_afterwards(list_check=lambda yielded: len(yielded) > 0)
#@assert_afterwards(count_check=lambda yielded: yielded > 0)
@assert_afterwards(any_check=True)
def random_select(iterations):
for index in range(iterations):
if random.randint(0, 9) > 4:
yield index
for _ in range(100):
for x in random_select(5):
print(x, flush=True, end=' ')
print()

上网试试!

Python没有这样的特性。

然而,如果你把代码的结构反转一点,迭代成功生成的范围内值而不是range(iterations),你可以简单地使用enumerate

def random_select(iterations):
values = (x 
for x in (random.randint(0, 9) for _ in range(iterations))
if x > 4)
count = 0
for count, v in enumerate(values, start=1):
yield v
assert count

(这只是您已经拥有的最微小的改进,因为您不需要手动增加count。)

您可以使用generator.send()并将几个生成器链接在一起。

import random
def inner(iterations, iterated=False):
for index in range(iterations):
if random.randint(0, 9) > 4:
iterated = yield
yield index
assert iterated
def random_select(iterations):
gen = inner(iterations)
yield from (gen.send(True) for _ in gen)
for i in random_select(2):
print(i)

在Python中,"使发电机串联在一起成为可能。它的行为与"yield"相同,除了它将生成器机制委托给子生成器。为了更好地理解,请看下面的代码。它允许将yield表达式移出主生成器,使重构更容易。

def subgen(x):
for i in range(x):
yield i
def gen(y):
yield from subgen(y)
for q in gen(6):
print(q)

输出将是05.

最新更新