[Twisted-Python] Callbacks, Looping, and Variable Binding
When I run the following code, everytime the callbacks to "onSuccess" get called, "item" is bound to the last element in "list". Obviously what I want is to have "item" bound to the value it had when I added the callback. How does one handle looping constructs like this in Twisted? def someFunc(): deferreds = [] def onSuccess(results): d = item.doSomethingElseThatReturnsDeferred() return d d = doSomethingThatReturnsDeferred() for item in list: d.addCallbacks(onSuccess, log.err) deferreds.append(d) return defer.DefferedList(deferreds)
On Thu, Jul 31, 2003 at 11:13:28AM -0600, Justin Johnson wrote:
When I run the following code, everytime the callbacks to "onSuccess" get called, "item" is bound to the last element in "list". Obviously what I want is to have "item" bound to the value it had when I added the callback. How does one handle looping constructs like this in Twisted?
Then don't inherit the namespace of someFunc. You could even move onSuccess outside of someFunc, to make sure you don't do that by accident. Besides, you are adding the outer d to deferreds once per iteration. That's broken. What do you want? I don't know what you are trying to do, so here's a guess, in form of a similar example as your code:
def someFunc(): deferreds = []
def onSuccess(results): d = item.doSomethingElseThatReturnsDeferred() return d
d = doSomethingThatReturnsDeferred()
for item in list: d.addCallbacks(onSuccess, log.err) deferreds.append(d)
return defer.DefferedList(deferreds)
def onSuccess(item): d = item.doSomethingElseThatReturnsDeferred() return d def someFunc(listOfItems): deferreds = [] for item in listOfItems: d = doSomethingThatReturnsDeferred(item) d.addCallbacks(onSuccess, log.err) deferreds.append(d) return defer.DeferredList(deferreds) -- :(){ :|:&};:
On Thu, 31 Jul 2003 22:50:04 +0300, "Tommi Virtanen"
On Thu, Jul 31, 2003 at 11:13:28AM -0600, Justin Johnson wrote:
When I run the following code, everytime the callbacks to "onSuccess" get called, "item" is bound to the last element in "list". Obviously what I want is to have "item" bound to the value it had when I added the callback. How does one handle looping constructs like this in Twisted?
Then don't inherit the namespace of someFunc. You could even move onSuccess outside of someFunc, to make sure you don't do that by accident.
My problem (besides just having a lot to learn) was that I was writing the callbacks to use variables that were defined in the loop, thinking I had no other option besides using results passed by previous callbacks. The results that were returned from doSomethingThatReturnsDeferred (and thus were arguments to the next callback) were needed (not right away, but I wanted the results to continue being passed down the callback chain), and I wasn't aware of any other way to get "item" passed to my callback. However, I tried using callbackArgs to pass "item" in a tuple, like this... for item in list: d.addCallbacks(onSuccess, log.err, callbackArgs=(item,)) deferreds.append(d) and then defining onSuccess like... def onSuccess(results, args): item = args[0] d = item.doSomethingElseThatReturnsDeferred() return d Is this an acceptable way to accomplish this? It is working in my code but I'd like to do things the right way.
Besides, you are adding the outer d to deferreds once per iteration. That's broken.
I'm not sure what you mean here. I was adding my deferred to a list and it seemed to be doing what I wanted (at least I think it was). Your help is appreciated. -Justin
Besides, you are adding the outer d to deferreds once per iteration. That's broken.
I'm not sure what you mean here. I was adding my deferred to a list and it seemed to be doing what I wanted (at least I think it was).
To clarify, what I'm trying to do here is create a bunch of Deferred's that aren't dependent on each other, and then put them in a DeferredList so I can add a callback to the list which will only fire when all Deferred's in the list are done. Does that make sense?
On Thu, Jul 31, 2003 at 02:20:24PM -0600, Justin Johnson wrote:
for item in list: d.addCallbacks(onSuccess, log.err, callbackArgs=(item,)) deferreds.append(d)
and then defining onSuccess like...
def onSuccess(results, args): item = args[0] d = item.doSomethingElseThatReturnsDeferred() return d
Is this an acceptable way to accomplish this? It is working in my code but I'd like to do things the right way.
Yes. I'd make that prettier with def onSuccess(results, item): d = item.doSomethingElseThatReturnsDeferred() return d ... for item in list: d.addCallback(onSuccess, item) d.addErrback(log.err) deferreds.append(d)
Besides, you are adding the outer d to deferreds once per iteration. That's broken. I'm not sure what you mean here. I was adding my deferred to a list and it seemed to be doing what I wanted (at least I think it was).
Your original code had
d = doSomethingThatReturnsDeferred()
for item in list: d.addCallbacks(onSuccess, log.err) deferreds.append(d)
Which ends up adding the _same_ d len(list) times to deferreds. -- :(){ :|:&};:
Yes. I'd make that prettier with
def onSuccess(results, item): d = item.doSomethingElseThatReturnsDeferred() return d ... for item in list: d.addCallback(onSuccess, item) d.addErrback(log.err) deferreds.append(d)
Yes, that looks much cleaner.
Besides, you are adding the outer d to deferreds once per iteration. That's broken. I'm not sure what you mean here. I was adding my deferred to a list and it seemed to be doing what I wanted (at least I think it was).
Your original code had
d = doSomethingThatReturnsDeferred()
for item in list: d.addCallbacks(onSuccess, log.err) deferreds.append(d)
Which ends up adding the _same_ d len(list) times to deferreds.
Ahhh.... I see. That was a result of me rewriting my code for the post to this list, and not putting things in their original place. Thanks for your help.
participants (2)
-
Justin Johnson
-
Tommi Virtanen