My function throw me with the local variable 'pt' referenced before assignment
error:
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.
Edit
The reason why you cannot reproduce the error might because of the over-simplify, as mentioned by @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
incallback
; Python determines the scope of a name at compile time and assignment makes this a local name.Unless you tell Python otherwise, that is. In Python 2, you can only mark a name explicitly as a
global
instead, you need Python 3 to be able to use thenonlocal
keyword:With the
nonlocal pt
line Python is explicitly told not to treatpt
as a local name but to take it from the enclosing scope ofget_audio_callback
instead.In Python 2, you can just create a local that takes its value from the closure:
because your enclosing
get_audio_callback
scope doesn't appear to usept
anyway and won't need access to the updatedpt_local
value.If you do need
pt
to update at theget_audio_callback
scope (if, say,callback
is called multiple times and you needpt
to be updated from call to call), you need to avoid usingpt
as a local inside thecallback
function altogether.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:Here
callback.pt
is no longer a local name; it is an attribute on thecallback
function object instead.It turned out to be a problem about 'reference'
I changed my code into passing
pt
by variable, and it worked out fine.