好程式員分享循環内的回調函數,問題出現在循環體内的回調函數,用一個很簡單的例子舉例:
for x in xrange(3):
1.
print "requests begin:%s"%x
2.
def callback(respon):
3.
print x
4.
print respon.body
5.
client.fetch("http://httpbin.org/get?x=%s" % x, callback)
此例子忽略了等待回調函數完成的wait實作(不實作這個會導緻作為單個檔案運作的時候,還沒獲得結果就退出了),在tornado.testing中的AsyncTestCase提供了相關功能
httpbin.org/get這個位址的作用是傳回了請求的json對象,形如:
{
"args": {
"x": "0"
},
"headers": {
"Accept-Encoding": "gzip",
6.
"Connection": "close",
7.
"Host": "httpbin.org",
8.
"X-Request-Id": "95df3c15-7ed0-4a6d-830d-fb9629e66515"
9.
10.
"origin": "192.81.129.91",
11.
"url": "http://httpbin.org/get?x=0"
12.
}
但實際上,由于回調函數特殊的特性:通路閉包内局部變量的目前值。易知,在第一個請求
http://httpbin.org/get?x=0
的url傳回時,循環早已結束,此時的x已經為2,是以實際上雖然httpbin.org傳回的json告訴我們,get參數裡的x為0,但閉包内通路到的x已經是2了
解決方法我想了兩個,一個是利用回調函數構造時的變量空間,在構造函數時即産生這個參數,形如:
client = AsyncHTTPClient(self.io_loop)
def callback(respon,num=x):
print x, num
if num == 2:
self.stop()
client.fetch("http://httpbin.org/get?x=%s" % x, wrap(x))
一種是再包一層閉包(這層閉包也可以放在for外面):
def wrap(number):
num = number
return callback
#wrap放在for外面:
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
client.fetch("http://httpbin.org/get?x=%s" % x, wrap(x))
思索了一下,閉包的記憶體占用問題應當是不可避免的?當循環體的每一項(x)是一個大記憶體對象時,記憶體占用等同于不用疊代器用清單進行循環,除了這兩種不知道還有沒有更優雅的解決方案。。