如何使用{单键:多个值}创建HTTP请求数据

And*_*son 1 python dictionary python-2.7 python-3.x python-requests

我需要发送HTTP带有数据的POST请求,如下所示:

data = {'id[]': '1', 'id[]': '2', 'id[]': '3'}
Run Code Online (Sandbox Code Playgroud)

值列表实际上是未知的,但是随它去吧 values_list = ['1', '2', '3']

当然要尝试

for value in values_list:
    data["id[]"] = value
Run Code Online (Sandbox Code Playgroud)

我得到的{'id[]': '3'}是键值对在每次迭代时都会被覆盖...

我使用了以下解决方案:

data = {}

class data_keys(object):
    def __init__(self, data_key):
        self.data_key = data_key

for value in values_list:
    data[data_keys('id[]')] = value
Run Code Online (Sandbox Code Playgroud)

但是我的data模样

{<__main__.data_keys object at 0x0000000004BAE518>: '2',
 <__main__.data_keys object at 0x0000000004BAED30>: '1',
 <__main__.data_keys object at 0x0000000004B9C748>: '3'}
Run Code Online (Sandbox Code Playgroud)

我的代码有什么问题?我还能怎么简单地用单键创建字典?

更新

这是我的HTTP请求的样子:

requests.post(url, data={"id[]": '1', "id[]": '2', "id[]": '3'}, auth=HTTPBasicAuth(user_name, user_passw))
Run Code Online (Sandbox Code Playgroud)

标题已更新

PM *_*ing 5

为了让你的data_keys类做你想做的事,你需要给它一个适当的__repr__方法__str__。这将允许在打印字典或其他代码尝试序列化它时以所需的方式显示类实例。

这是一个简短的演示,它使用第 3 方请求模块来构建 URL。我更改了类名,使其符合通常的 Python 类命名约定。此代码在 Python 2.6 和 Python 3.6 上进行了测试

from __future__ import print_function
import requests

class DataKey(object):
    def __init__(self, data_key):
        self.data_key = data_key

    def __repr__(self):
        return str(self.data_key)

data = {}
values_list = ['1', '2', '3']

for value in values_list:
    data[DataKey('id[]')] = value

print(data)

req = requests.get(url='http://www.example.com', params=data)
print(req.url)
Run Code Online (Sandbox Code Playgroud)

输出

{id[]: '1', id[]: '2', id[]: '3'}
http://www.example.com/?id%5B%5D=1&id%5B%5D=2&id%5B%5D=3
Run Code Online (Sandbox Code Playgroud)

这是一个更强大的版本,灵感来自 Rogalski 的答案,该版本可以被json模块接受。

from __future__ import print_function
import requests
import json

class DataKey(str):
    def __init__(self, data_key):
        self.data_key = data_key

    def __repr__(self):
        return str(self.data_key)

    def __eq__(self, other):
        return self is other

    def __hash__(self):
        return id(self)

data = {}
values_list = ['1', '2', '3']

for value in values_list:
    data[DataKey('id[]')] = value

print(data)

req = requests.get(url='http://www.example.com', params=data)
print(req.url)

print(json.dumps(data))
Run Code Online (Sandbox Code Playgroud)

输出

{id[]: '3', id[]: '1', id[]: '2'}
http://www.example.com/?id%5B%5D=3&id%5B%5D=1&id%5B%5D=2
{"id[]": "3", "id[]": "1", "id[]": "2"}
Run Code Online (Sandbox Code Playgroud)

正如我在对该问题的评论中提到的,这很奇怪,并且使用多个(伪)相同键创建字典实际上并不是一件非常有用的事情。几乎总会有更好的方法,例如使用dict列表或元组,或者在本例中,提供提供数据的替代方法,如 Poke 的答案所示。

但是,我应该提到, JSON 对象中并不禁止多个相同的键,因此有时可能需要处理此类 JSON 数据。我并不是使用这些疯狂的词典是一个好方法,但这有可能的......


pok*_*oke 5

尽管您可以修改字典键以允许看似“相等”的键,但这可能不是一个好主意,因为这依赖于如何将键转换为字符串的实现细节。此外,如果您需要调试这种情况,肯定会引起混乱。

实际上,表单数据编码机制中内置了一个更加容易且受支持的解决方案:您可以简单地传递值列表:

data = {
    'id[]': ['1', '2', '3']
}

req = requests.get(url='http://www.example.com', params=data)
print(req.url) # 'http://www.example.com/?id%5B%5D=1&id%5B%5D=2&id%5B%5D=3'
Run Code Online (Sandbox Code Playgroud)

因此,您只需将您的密码values_list直接传递到字典中,一切就可以正常工作,而无需修改任何内容。


并且,如果您发现自己认为这样的字典不起作用,则还可以提供两个元组的迭代器(第一个值是键,第二个值是键):

data = [
    ('id[]', '1'),
    ('id[]', '2'),
    ('id[]', '3')
]

req = requests.get(url='http://www.example.com', params=data)
print(req.url) # 'http://www.example.com/?id%5B%5D=1&id%5B%5D=2&id%5B%5D=3'
Run Code Online (Sandbox Code Playgroud)