python - 为什么 python 3.6's aiohttp' s 循环多次给出相同的结果?

标签 python python-3.x python-asyncio aiohttp

我想使用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包含对字典的引用(“指针”)。 text.append(d) 语句只是将同一字典的引用添加到列表中。因此,经过 N 次迭代后,列表中有 N 个对 d 的相同引用。

如果你将循环更改为如下所示:

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?)。

关于python - 为什么 python 3.6's aiohttp' s 循环多次给出相同的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45006518/

相关文章:

python - 第一次完成后取消两个异步协程

python - 为什么 pyzmq 订阅者与 asyncio 的行为不同?

python - python中左右键的其他 "codes"是什么?

python - 无法使用 Pipenv 缓存 Github Actions 上的依赖项

python - 在 DataFrame 中获取前一个工作日

python - 将 csv 读入字典,每个值有 2 个键

python - 如何使用 Windows 身份验证在 IIS 服务器上的 Flask 应用程序中获取当前用户的用户名?

python - 后向差分编码

python - 如果 row[index] == "String"python 将行写入新的 csv

Python (3.7+) 多处理 : replace Pipe connection between master and workers with asyncio for IO concurrency