未执行的 yield 语句块函数到 运行?
Unexecuted yield statement blocks function to run?
在下面的简化代码中,我想重用一个循环来先做一个准备并产生结果。
但是,准备 (bar()
) 函数永远不会执行。
yield 语句是否改变了函数的流程?
def bar(*args,**kwargs):
print("ENTER bar")
pass
def foo(prepare=False):
print("ENTER foo")
for x in range(1,10):
if prepare:
bar(x)
else:
yield x
foo(prepare=True)
r = foo(prepare=False)
for x in r:
pass
因为 foo
定义包含一个 yield,它不会 运行 像一个普通函数,即使你像一个函数一样调用它(例如 foo(prepare=True)
)。
运行 foo()
带有任何参数都会 return 生成器对象,适合迭代。在您尝试迭代该生成器对象之前,定义的主体不会是 运行。
new coroutine syntax 在定义的 start 处放置了一个关键字,因此本质上的变化不会隐藏在函数体内。
问题是 yield
语句会将函数更改为返回生成器并改变函数的行为。
基本上这意味着在调用生成器的 .next
函数时函数执行到 yield
或函数终止(在这种情况下它引发 StopIteration
异常).
因此,您应该做的是确保即使无法达到 yield
语句也能对其进行迭代。喜欢:
r = foo(prepare=True)
for x in r:
pass
在这种情况下,循环将立即终止,因为没有到达 yield
语句。
在我看来,这里的实际解释是:
Python 懒惰地评估 if
条件!
我会解释:
当你打电话给
foo(prepare=True)
就这样,什么也没有发生,尽管你可能认为 bar(x)
会被执行 10 次。但真正发生的是 'no-one' 要求 foo(prepare=True)
调用的 return 值,因此 if
未被评估,但如果您使用 return 则可能来自 foo
.
的值
在对 foo
的第二次调用中,迭代 return 值 r
,python 必须计算 return 值,它确实如此,我会证明:
案例一
r = foo(prepare=True)
for x in r:
pass
这里输出'ENTER bar'9次。这意味着 bar
被执行了 9 次。
案例二
r = foo(prepare=False)
for x in r:
pass
在这种情况下,没有像预期的那样打印“ENTER bar”。
总而言之,我会说:
有些情况下Python执行Lazy Evaluation, one of them is the if
statement.
在 Python,
中并不是所有的东西都是惰性求值的
例如:
# builds a big list and immediately discards it
sum([x*x for x in xrange(2000000)])
对比
# only keeps one value at a time in memory
sum(x*x for x in xrange(2000000))
关于 python 中的懒惰和热切求值,继续阅读 here。
在下面的简化代码中,我想重用一个循环来先做一个准备并产生结果。
但是,准备 (bar()
) 函数永远不会执行。
yield 语句是否改变了函数的流程?
def bar(*args,**kwargs):
print("ENTER bar")
pass
def foo(prepare=False):
print("ENTER foo")
for x in range(1,10):
if prepare:
bar(x)
else:
yield x
foo(prepare=True)
r = foo(prepare=False)
for x in r:
pass
因为 foo
定义包含一个 yield,它不会 运行 像一个普通函数,即使你像一个函数一样调用它(例如 foo(prepare=True)
)。
运行 foo()
带有任何参数都会 return 生成器对象,适合迭代。在您尝试迭代该生成器对象之前,定义的主体不会是 运行。
new coroutine syntax 在定义的 start 处放置了一个关键字,因此本质上的变化不会隐藏在函数体内。
问题是 yield
语句会将函数更改为返回生成器并改变函数的行为。
基本上这意味着在调用生成器的 .next
函数时函数执行到 yield
或函数终止(在这种情况下它引发 StopIteration
异常).
因此,您应该做的是确保即使无法达到 yield
语句也能对其进行迭代。喜欢:
r = foo(prepare=True)
for x in r:
pass
在这种情况下,循环将立即终止,因为没有到达 yield
语句。
在我看来,这里的实际解释是:
Python 懒惰地评估 if
条件!
我会解释:
当你打电话给
foo(prepare=True)
就这样,什么也没有发生,尽管你可能认为 bar(x)
会被执行 10 次。但真正发生的是 'no-one' 要求 foo(prepare=True)
调用的 return 值,因此 if
未被评估,但如果您使用 return 则可能来自 foo
.
在对 foo
的第二次调用中,迭代 return 值 r
,python 必须计算 return 值,它确实如此,我会证明:
案例一
r = foo(prepare=True)
for x in r:
pass
这里输出'ENTER bar'9次。这意味着 bar
被执行了 9 次。
案例二
r = foo(prepare=False)
for x in r:
pass
在这种情况下,没有像预期的那样打印“ENTER bar”。
总而言之,我会说:
有些情况下Python执行Lazy Evaluation, one of them is the
if
statement.在 Python,
中并不是所有的东西都是惰性求值的
例如:
# builds a big list and immediately discards it
sum([x*x for x in xrange(2000000)])
对比
# only keeps one value at a time in memory
sum(x*x for x in xrange(2000000))
关于 python 中的懒惰和热切求值,继续阅读 here。