urlencode()编码嵌套字典
Python的urllib.parse提供了urlencode()方法,可以直接将字典转换成URL字符串。
但是使用时发现它只能处理一维字典,转换嵌套字典时就会出错。如下:
from urllib import parse
payload = {"status": 200,
"body": {"id": 1,
"msg": "hello"}
}
url_str = parse.urlencode(payload) # 编码成URL字符串
print(url_str)
print(parse.unquote(url_str)) # 恢复成Unicode字符串
其显示为:
status=200&body=%7B%27id%27%3A+1%2C+%27msg%27%3A+%27hello%27%7D
status=200&body={'id':+1,+'msg':+'hello'}
可见urlencode()处理内层字典时会出错。
用PHP生成URL字符串
嵌套字典转换成URL字符串之后应该是什么样子?这里用PHP生成它看看。
PHP的http_build_query()与Python的urlencode()都是采用RFC3986规范。
<?php
$payload = array("status"=> 200,
"body" => array("id"=> 1,
"msg"=> "hello")
);
$url_str = http_build_query($payload, '', '&', PHP_QUERY_RFC3986);
echo $url_str; // 编码成URL字符串
echo PHP_EOL;
echo urldecode($url_str); // 恢复成Unicode字符串
?>
其显示为:
status=200&body%5Bid%5D=1&body%5Bmsg%5D=hello
status=200&body[id]=1&body[msg]=hello
将Python的嵌套字典变成一维,以便urlencode
编写个处理函数,将嵌套的内层字典展开,转换成一维字典,然后再由parse.urlencode()处理。
from urllib import parse
def flat_key(layer):
""" Example: flat_key(["1","2",3,4]) -> "1[2][3][4]" """
if len(layer) == 1:
return layer[0]
else:
_list = ["[{}]".format(k) for k in layer[1:]]
return layer[0] + "".join(_list)
def flat_dict(_dict):
if not isinstance(_dict, dict):
raise TypeError("argument must be a dict, not {}".format(type(_dict)))
def __flat_dict(pre_layer, value):
result = {}
for k, v in value.items():
layer = pre_layer[:]
layer.append(k)
if isinstance(v, dict):
result.update(__flat_dict(layer,v))
else:
result[flat_key(layer)] = v
return result
return __flat_dict([], _dict)
if __name__=="__main__":
payload = {"status": 200,
"body": {"id": 1,
"msg": "hello"}
}
url_str = parse.urlencode(flat_dict(payload)) # 编码成URL字符串
print(url_str)
print(parse.unquote(url_str)) # 恢复成Unicode字符串
其显示为:
status=200&body%5Bid%5D=1&body%5Bmsg%5D=hello
status=200&body[id]=1&body[msg]=hello
可见生成的URL字符串与PHP相同。