Reputation: 46513
I have this situation:
module1.py
:
class AudioEngine:
def __init__(self):
self.liverecording = False
def getaudiocallback(self):
def audiocallback(in_data, frame_count, time_info, status): # these 4 parameters are requested by pyaudio
data = None # normally here we process the audio data
if self.liverecording:
print("Recording...")
return data
return audiocallback
main.py
:
import module1
a = module1.AudioEngine()
f = a.getaudiocallback()
f(0, 0, 0, 0)
a.liverecording = True
f(0, 0, 0, 0) # prints "Recording...", which is the expected behaviour, but why does it work?
Question: How to make the callback function audiocallback(...)
change accordingly to the new value of a.liverecording
? If it works out of the box, why does it?
More specifically, does f
, once created with f = a.getaudiocallback()
, keep in his code a pointer to a.liverecording
(so if the latter is modified, this will be taken into consideration), or a copy of the value of a.liverecording
(i.e. False
) at the time of the creation of f
?
Upvotes: 1
Views: 529
Reputation: 365807
If you understand closures, the only trick here is that the local variable you're capturing in your closure is the self
parameter inside getaudiocallback
.
Inside that method, the self
is of course the AudioEngine
instance a
. So, the value of the variable that you've captured is that same instance.
In fact, Python lets you reflect on almost everything at runtime, so you can see this directly:
>>> f = a.getaudiocallback()
>>> f
<function __main__.AudioEngine.getaudiocallback.<locals>.audiocallback(in_data, frame_count, time_info, status)>
>>> f.__closure__[0].cell_contents
<__main__.AudioEngine at 0x11772b3c8>
>>> f.__closure__[0].cell_contents is a
True
If getaudiocallback
were still live, and it rebound self
to some other value, that f.__closure__[0]
would update to point to the new value of self
. Since it's already exited, that's never going to happen; the cell will always be pointing at the instance that was in a
at the time the method was called.
But if that instance later gets mutated, as when you write a.liverecording = True
, of course you can see that.
Upvotes: 2