Skip to main content
 首页 » 编程设计

python之将局部变量添加到正在运行的生成器

2025年05月04日16lyhabc

最近,我尝试从正在运行的生成器外部设置局部变量。生成器代码也应该访问这些变量。

一个麻烦是,当访问变量时,解释器认为它必须是全局变量,因为变量没有在本地范围内设置。但我不想更改全局变量,也不想复制整个全局范围以人为地使变量成为局部变量。

另一个问题是,当从外部访问时,本地词典(和全局词典?)接缝为只读。

是否有任何合法(或至少部分合法的方式)将局部变量引入正在运行的生成器实例?

编辑澄清:

我指的不是“发送”功能。这当然是一个简洁的函数,但由于我想设置多个具有不同名称的变量,这对我的目的来说并不方便。

请您参考如下方法:

您可能正在寻找的是 send方法,它允许将值发送到生成器。 The reference举个例子:

>>> def echo(value=None): 
...     print "Execution starts when 'next()' is called for the first time." 
...     try: 
...         while True: 
...             try: 
...                 value = (yield value) 
...             except Exception, e: 
...                 value = e 
...     finally: 
...         print "Don't forget to clean up when 'close()' is called." 
... 
>>> generator = echo(1) 
>>> print generator.next() 
Execution starts when 'next()' is called for the first time. 
1 
>>> print generator.next() 
None 
>>> print generator.send(2) 
2 
>>> generator.throw(TypeError, "spam") 
TypeError('spam',) 
>>> generator.close() 
Don't forget to clean up when 'close()' is called. 

让我举一个我自己的例子。 (注意!上面的代码是Python 2.6,但下面我会写Python 3;py3k ref):

>>> def amplify(iter, amp=1): 
...     for i in iter: 
...         reply = (yield i * amp) 
...         amp = reply if reply != None else amp  
...  
>>> it = amplify(range(10)) 
>>> next(it) 
0 
>>> next(it) 
1 
>>> it.send(3) # 2 * 3 = 6 
6 
>>> it.send(8) # 3 * 8 = 24 
24 
>>> next(it) # 4 * 8 = 32 
32 

当然,如果你真的想要,你也可以不使用send。例如。通过将生成器封装在一个类中(但它并不那么优雅!):

>>> class MyIter: 
...     def __init__(self, iter, amp=1): 
...         self.iter = iter 
...         self.amp = amp 
...     def __iter__(self): 
...         for i in self.iter: 
...             yield i * self.amp 
...     def __call__(self): 
...         return iter(self) 
...  
>>> iterable = MyIter(range(10)) 
>>> iterator = iterable() 
>>> next(iterator) 
0 
>>> next(iterator) 
1 
>>> iterable.amp = 3 
>>> next(iterator) 
6 
>>> iterable.amp = 8 
>>> next(iterator) 
24 
>>> next(iterator) 
32 

更新:好的,现在您已经更新了您的问题,让我再试一下这个问题。也许这就是你的意思?

>>> def amplify(iter, loc={}): 
...     for i in iter: 
...         yield i * loc.get('amp', 1) 
...  
>>> it = amplify(range(10), locals()) 
>>> next(it) 
0 
>>> next(it) 
1 
>>> amp = 3 
>>> next(it) 
6 
>>> amp = 8 
>>> next(it) 
24 
>>> next(it) 
32 

请注意 locals()应该被视为只读的并且是范围相关的。如您所见,您需要将 locals() 显式传递给生成器。我看不出解决这个问题的办法......