为什么 python 3.6 的 aiohttp 的循环多次给出相同的结果?
Why python 3.6's aiohttp's loop just gives the same result for many time?
我想使用 aiohttp 作为一个简单的 http 服务器来响应客户端的 http 获取结果:
客户端发送这样的 http get 请求
curl 'http://localhost:8081/query=192.168.1.1,18.9.8.1,10.3.4.5'
,
然后我的简单服务器响应结果如下
[{'ip': '192.168.1.1'}, {'ip': '18.9.8.1'}, {'ip': '10.3.4.5''}]
,
但实际上响应循环10.3.4.5 3次,很奇怪:
[{'ip': '10.3.4.5'}, {'ip': '10.3.4.5'}, {'ip': '10.3.4.5'}]
我的代码如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import asyncio
from aiohttp import web
async def index(request):
await asyncio.sleep(0)
return web.Response(body=b'''Usage Example: curl "http://xxxx/query=ip1[,ip2...]" ''')
async def query(request):
await asyncio.sleep(0)
ip_list = list(request.match_info['many_ip'].split(','))
text=[]
# d={"ip":None,"problem_appearance":"cpu.idle <= 10%","problem_rootcase":"来自10.1.1.2的如下慢SQL导致","begin_time":"2017-07-07 10:59:00","end_time":"2017-07-07 11:00:00","suggest_solution":"null"}
d={"ip":None}
for ip in ip_list:
d["ip"]=ip
print(d)
text.append(d)
print(text)
return web.Response(body=str(text))
async def init(loop):
port='8081'
app = web.Application(loop=loop)
app.router.add_route('GET', '/', index)
app.router.add_route('GET', '/query={many_ip}', query)
srv = await loop.create_server(app.make_handler(), '127.0.0.1', port)
print('Server started at http://127.0.0.1:{port}...'.format(port=port))
return srv
loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
loop.run_forever()
变量 d
包含对字典的引用 ("pointer")。 text.append(d)
语句只是将同一词典的引用添加到列表中。因此,在 N 次迭代之后,您在列表中对 d
有 N 个相同的引用。
如果你把循环变成这样:
for ip in ip_list:
d["ip"]=ip
text.append(d)
print(text)
你应该在控制台上看到:
[{'ip': '192.168.1.1'}]
[{'ip': '18.9.8.1'}, {'ip': '18.9.8.1'}]
[{'ip': '10.3.4.5'}, {'ip': '10.3.4.5'}, {'ip': '10.3.4.5'}]
这是因为 d
是一个引用,当您通过引用更改某些内容时,您会在使用相同引用的任何地方更改它。
要解决您的问题,您应该这样写:
for ip in ip_list:
d = {"ip" : ip}
print(d)
text.append(d)
在这种情况下,每次迭代都会创建一个新字典,并将对它的引用保存到 d
.
如果您需要使用已经在循环外创建的 d
,那么您应该使用字典的 copy()
方法。它创建保存在 d
中的字典的浅拷贝(有关浅拷贝和深拷贝的更多信息,您可以在此处找到:Understanding dict.copy() - shallow or deep?)。
我想使用 aiohttp 作为一个简单的 http 服务器来响应客户端的 http 获取结果:
客户端发送这样的 http get 请求
curl 'http://localhost:8081/query=192.168.1.1,18.9.8.1,10.3.4.5'
,
然后我的简单服务器响应结果如下
[{'ip': '192.168.1.1'}, {'ip': '18.9.8.1'}, {'ip': '10.3.4.5''}]
,
但实际上响应循环10.3.4.5 3次,很奇怪:
[{'ip': '10.3.4.5'}, {'ip': '10.3.4.5'}, {'ip': '10.3.4.5'}]
我的代码如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import asyncio
from aiohttp import web
async def index(request):
await asyncio.sleep(0)
return web.Response(body=b'''Usage Example: curl "http://xxxx/query=ip1[,ip2...]" ''')
async def query(request):
await asyncio.sleep(0)
ip_list = list(request.match_info['many_ip'].split(','))
text=[]
# d={"ip":None,"problem_appearance":"cpu.idle <= 10%","problem_rootcase":"来自10.1.1.2的如下慢SQL导致","begin_time":"2017-07-07 10:59:00","end_time":"2017-07-07 11:00:00","suggest_solution":"null"}
d={"ip":None}
for ip in ip_list:
d["ip"]=ip
print(d)
text.append(d)
print(text)
return web.Response(body=str(text))
async def init(loop):
port='8081'
app = web.Application(loop=loop)
app.router.add_route('GET', '/', index)
app.router.add_route('GET', '/query={many_ip}', query)
srv = await loop.create_server(app.make_handler(), '127.0.0.1', port)
print('Server started at http://127.0.0.1:{port}...'.format(port=port))
return srv
loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
loop.run_forever()
变量 d
包含对字典的引用 ("pointer")。 text.append(d)
语句只是将同一词典的引用添加到列表中。因此,在 N 次迭代之后,您在列表中对 d
有 N 个相同的引用。
如果你把循环变成这样:
for ip in ip_list:
d["ip"]=ip
text.append(d)
print(text)
你应该在控制台上看到:
[{'ip': '192.168.1.1'}]
[{'ip': '18.9.8.1'}, {'ip': '18.9.8.1'}]
[{'ip': '10.3.4.5'}, {'ip': '10.3.4.5'}, {'ip': '10.3.4.5'}]
这是因为 d
是一个引用,当您通过引用更改某些内容时,您会在使用相同引用的任何地方更改它。
要解决您的问题,您应该这样写:
for ip in ip_list:
d = {"ip" : ip}
print(d)
text.append(d)
在这种情况下,每次迭代都会创建一个新字典,并将对它的引用保存到 d
.
如果您需要使用已经在循环外创建的 d
,那么您应该使用字典的 copy()
方法。它创建保存在 d
中的字典的浅拷贝(有关浅拷贝和深拷贝的更多信息,您可以在此处找到:Understanding dict.copy() - shallow or deep?)。