[英]Python closure, local variable scope error
My function throw me with the local variable 'pt' referenced before assignment
error: 我的函数让我
local variable 'pt' referenced before assignment
错误local variable 'pt' referenced before assignment
了local variable 'pt' referenced before assignment
:
Traceback (most recent call last):
File "/home/solesschong/Workspace/PenPal/python/main.py", line 126, in callback
ind = (i+pt) % n
UnboundLocalError: local variable 'pt' referenced before assignment
the code is as follows 代码如下
def get_audio_callback(pt):
def callback(in_data, frame_count, time_info, status):
for i in range(frame_count):
ind = (i+pt) % n
return (a, b)
return callback
and in global scope, 在全球范围内
pt = 0
stream = p.open(stream_callback=get_audio_callback(pt))
I cannot figure out why the error occurs, since I've checked with some examples on closure and find no difference. 我无法弄清楚为什么会发生错误,因为我已经检查了一些有关闭包的示例,但没有发现任何区别。
The reason why you cannot reproduce the error might because of the over-simplify, as mentioned by @Martijn Pieters. 如@Martijn Pieters所述,您之所以无法重现该错误,可能是因为过于简化了。 Hence the original code.
因此是原始代码。
Further I've solved this problem by passing by reference, plz see my own answer. 此外,我已经通过引用的方式解决了这个问题,请参见我自己的答案。
"""
Sound API
"""
def get_audio_callback(pt):
def callback(in_data, frame_count, time_info, status):
"""
This is the callback function for sound API
In each call, synthesized data is dumpped into the sound buffer
"""
wave = np.ndarray((frame_count, 2))
for i in range(frame_count):
ind = (i+pt) % n
wave[i,0] = float(x[ind]) * 2
wave[i,1] = float(y[ind]) * 2
pt = pt + frame_count
return (encode(wave), pyaudio.paContinue)
return callback
p = pyaudio.PyAudio()
pt = 0
stream = p.open(format=pyaudio.paFloat32,
channels=2,
rate=RATE,
output=True,
stream_callback=get_audio_callback(pt))
Your code assigns to pt
in callback
; 您的代码在
callback
分配给pt
; Python determines the scope of a name at compile time and assignment makes this a local name. Python在编译时确定名称的范围,赋值使其成为本地名称。
pt = pt + frame_count
Unless you tell Python otherwise, that is. 除非您另外告诉Python,否则就是这样。 In Python 2, you can only mark a name explicitly as a
global
instead, you need Python 3 to be able to use the nonlocal
keyword: 在Python 2中,您只能将名称显式标记为
global
名称,而您需要Python 3才能使用nonlocal
关键字:
def callback(in_data, frame_count, time_info, status):
"""
This is the callback function for sound API
In each call, synthesized data is dumpped into the sound buffer
"""
nonlocal pt
wave = np.ndarray((frame_count, 2))
for i in range(frame_count):
ind = (i+pt) % n
wave[i,0] = float(x[ind]) * 2
wave[i,1] = float(y[ind]) * 2
pt = pt + frame_count
return (encode(wave), pyaudio.paContinue)
With the nonlocal pt
line Python is explicitly told not to treat pt
as a local name but to take it from the enclosing scope of get_audio_callback
instead. 在
nonlocal pt
行中,明确告知Python不要将pt
视为本地名称,而get_audio_callback
的封闭范围中get_audio_callback
。
In Python 2, you can just create a local that takes its value from the closure: 在Python 2中,您可以创建一个从闭包中获取其值的本地:
def callback(in_data, frame_count, time_info, status):
"""
This is the callback function for sound API
In each call, synthesized data is dumpped into the sound buffer
"""
pt_local = pt
wave = np.ndarray((frame_count, 2))
for i in range(frame_count):
ind = (i+pt_local) % n
wave[i,0] = float(x[ind]) * 2
wave[i,1] = float(y[ind]) * 2
pt_local = pt_local + frame_count
return (encode(wave), pyaudio.paContinue)
because your enclosing get_audio_callback
scope doesn't appear to use pt
anyway and won't need access to the updated pt_local
value. 因为您
get_audio_callback
范围似乎仍然不使用pt
,并且不需要访问更新的pt_local
值。
If you do need pt
to update at the get_audio_callback
scope (if, say, callback
is called multiple times and you need pt
to be updated from call to call), you need to avoid using pt
as a local inside the callback
function altogether. 如果确实需要
pt
在get_audio_callback
范围内进行更新(例如,如果多次callback
,并且需要从一次调用到另一次更新pt
),则需要避免将pt
用作callback
函数内部的本地对象。
One effective work-around for that is to wrap the value in a mutable object or assign it as a mutable attribute somewhere that both the enclosing scope and the local scope can access it without it ever being seen as a local assignment. 一种有效的解决方法是将值包装在可变对象中,或将其分配为可变属性,以使封闭范围和本地范围都可以访问该值,而不会将其视为本地赋值。 Setting an attribute on the
callback
function is a good way to do that: 在
callback
函数上设置属性是执行此操作的好方法:
def get_audio_callback(pt):
def callback(in_data, frame_count, time_info, status):
"""
This is the callback function for sound API
In each call, synthesized data is dumpped into the sound buffer
"""
wave = np.ndarray((frame_count, 2))
for i in range(frame_count):
ind = (i+callback.pt) % n
wave[i,0] = float(x[ind]) * 2
wave[i,1] = float(y[ind]) * 2
callback.pt = callback.pt + frame_count
return (encode(wave), pyaudio.paContinue)
callback.pt = pt
return callback
Here callback.pt
is no longer a local name; 这里的
callback.pt
不再是本地名称; it is an attribute on the callback
function object instead. 它是
callback
函数对象上的一个属性。
It turned out to be a problem about 'reference' 原来是关于“参考”的问题
I changed my code into passing pt
by variable, and it worked out fine. 我将代码更改为通过变量传递
pt
,效果很好。
pt = [0]
def get_audio_callback(pt_ref):
def callback(in_data, frame_count, time_info, status):
pt = pt_ref[0]
for i in range(frame_count):
ind = (i+pt) % n
return (a, b)
return callback
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.