Iterating a loop using await or yield causes error
<p>I come from the land of <code>Twisted</code>/<a href="https://github.com/twisted/klein" rel="nofollow"><code>Klein</code></a>. I come in peace and to ask for <code>Tornado</code> help.  I'm investigating Tornado and how its take on async differs from Twisted.  Twisted has something similar to <code>gen.coroutine</code> which is <a href="http://twistedmatrix.com/documents/current/core/howto/defer-intro.html#inline-callbacks-using-yield" rel="nofollow"><code>defer.inlineCallbacks</code></a> and I'm able to write async code like this:</p>

<p><em>kleinsample.py</em></p>

<pre><code>@app.route('/endpoint/&lt;int:n&gt;')
@defer.inlineCallbacks
def myRoute(request, n):
    jsonlist = []
    for i in range(n):
        yield jsonlist.append({'id': i})
    return json.dumps(jsonlist)
</code></pre>

<p>curl cmd:</p>

<pre><code>curl localhost:9000/json/2000
</code></pre>

<p>This endpoint will create a JSON string with <code>n</code> number of elements.  <code>n</code> can be small or very big.  I'm able to break it up in Twisted such that the event loop won't block using <code>yield</code>.  Now here's how I tried to convert this into Tornado:</p>

<p><em>tornadosample.py</em></p>

<pre><code>async def get(self, n):
    jsonlist = []
    for i in range(n):
        await gen.Task(jsonlist.append, {'id': i})    # exception here
    self.write(json.dumps(jsonlist))
</code></pre>

<p>The traceback:</p>

<pre><code> TypeError: append() takes no keyword arguments
</code></pre>

<p>I'm confused about what I'm supposed to do to properly iterate each element in the loop so that the event loop doesn't get blocked.  Does anyone know the "Tornado" way of doing this?</p>

<p>Let's have a look at <code>gen.Task</code> <a href="http://www.tornadoweb.org/en/stable/gen.html#tornado.gen.Task" rel="nofollow">docs</a>:</p>

<blockquote>
  <p>Adapts a callback-based asynchronous function for use in coroutines.</p>
  
  <p>Takes a function (and optional additional arguments) and runs it with those arguments <strong>plus a callback keyword argument</strong>. The argument passed to the callback is returned as the result of the yield expression.</p>
</blockquote>

<p>Since <code>append</code> doesn't accept a keyword argument it doesn't know what to do with that <code>callback</code> kwarg and spits that exception.</p>

<p>What you could do is wrap <code>append</code> with your own function that does accept a <code>callback</code> kwarg or the approach showed in <a href="http://stackoverflow.com/a/11683014/1453822">this</a> answer.</p>

python python-3.x asynchronous tornado coroutine