Python 将局部变量添加到正在运行的生成器
最近,我尝试从运行的生成器外部设置局部变量。生成器代码也应该访问这些变量 一个问题是,当访问变量时,解释程序认为它必须是全局变量,因为变量没有设置在局部范围内。但是我不想改变全局变量,也不想复制整个全局范围来人为地使变量局部化 另一个问题是,当从外部访问时,本地(和全球?)词典被绑定为只读 是否有任何合法(或至少部分合法)的方式将局部变量引入正在运行的生成器实例 编辑以澄清: 我不是说“发送”功能。这当然是一个简洁的函数,但由于我想用不同的名称设置多个变量,因此对我来说并不方便。locals()始终返回只读dict。您可以创建自己的“locals”字典:Python 将局部变量添加到正在运行的生成器,python,variables,generator,local,Python,Variables,Generator,Local,最近,我尝试从运行的生成器外部设置局部变量。生成器代码也应该访问这些变量 一个问题是,当访问变量时,解释程序认为它必须是全局变量,因为变量没有设置在局部范围内。但是我不想改变全局变量,也不想复制整个全局范围来人为地使变量局部化 另一个问题是,当从外部访问时,本地(和全球?)词典被绑定为只读 是否有任何合法(或至少部分合法)的方式将局部变量引入正在运行的生成器实例 编辑以澄清: 我不是说“发送”功能。这当然是一个简洁的函数,但由于我想用不同的名称设置多个变量,因此对我来说并不方便。locals()
def gen_func():
lcls = {}
for i in range(5):
yield (i, lcls)
print lcls
for (val, lcls) in gen_func():
lcls[val] = val
任何其他可变结构也可以使用。locals()始终返回只读dict。您可以创建自己的“locals”字典:
def gen_func():
lcls = {}
for i in range(5):
yield (i, lcls)
print lcls
for (val, lcls) in gen_func():
lcls[val] = val
任何其他可变结构也可以工作。您可能正在寻找的是允许将值发送到生成器的方法。提供了一个示例:
>>> 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;):
>>> 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
当然,如果您真的愿意,您也可以在不发送的情况下执行此操作。例如,通过将生成器封装在一个类中(但它没有那么优雅!):
更新:好的,既然你已经更新了你的问题,让我再尝试一下这个问题。也许这就是你的意思
>>> 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()
传递给生成器。我看没有办法解决这个问题……您可能正在寻找的是允许将值发送到生成器的方法。提供了一个示例:
>>> 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;):
>>> 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
当然,如果您真的愿意,您也可以在不发送的情况下执行此操作。例如,通过将生成器封装在一个类中(但它没有那么优雅!):
更新:好的,既然你已经更新了你的问题,让我再尝试一下这个问题。也许这就是你的意思
>>> 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()
传递给生成器。我看没有办法解决这个问题…如果您想要一个同时充当接收器的协程或生成器,您应该使用send方法,如中所示。如果要通过设置生成器中的各种属性来更改运行时行为,有一个由Raymond Hettinger编写的旧版本:
def foo_iter(self):
self.v = "foo"
while True:
yield self.v
enableAttributes(foo_iter)
it = foo_iter()
print it.next()
it.v = "boo"
print it.next()
这将打印:
foo
boo
将enableAttributes
函数转换为适当的修饰符应该不会太困难 如果您希望有一个同时充当接收器的协程或生成器,则应使用send方法,如中所示。如果要通过设置生成器中的各种属性来更改运行时行为,有一个由Raymond Hettinger编写的旧版本:
def foo_iter(self):
self.v = "foo"
while True:
yield self.v
enableAttributes(foo_iter)
it = foo_iter()
print it.next()
it.v = "boo"
print it.next()
这将打印:
foo
boo
将enableAttributes
函数转换为适当的修饰符应该不会太困难 谢谢你提供了很长的例子。在我的问题的第一次编辑中,我忘了在这里添加关于“发送”的注释。好的,我现在添加了另一个版本,带有locals()
。也许这适合你的需要?谢谢你提供了很长的例子。在我的问题的第一次编辑中,我忘了在这里添加关于“发送”的注释。好的,我现在添加了另一个版本,带有locals()
。也许这适合你的需要?嗨,托斯滕,谢谢,这真的很接近我想要做的。我不知道那个食谱,它对我来说真的很有趣(必须在一个安静的小时内仔细检查)。不过,在生成器编码中有一些更方便的东西还是不错的……嗨,托尔斯滕,谢谢,这真的很接近我想要做的。我不知道那个食谱,它对我来说真的很有趣(必须在一个安静的小时内仔细检查)。不过,在生成器编码中有一些更方便的东西还是不错的。。。