urlencode многомерный словарь в python

Как я могу получить версию многомерного словаря в Python с URL-кодировкой? К сожалению, urllib.urlencode() работает только в одном измерении. Мне нужна версия, способная рекурсивно кодировать словарь.

Например, если у меня есть следующий словарь:

 {'a': 'b', 'c': {'d': 'e'}} 

Я хочу получить следующую строку:

 a=b&c[d]=e 

  • Лучший способ получить строку запроса из URL-адреса в python?
  • Запросы URLDecoding
  • Как передать несколько значений для одного параметра URL?
  • Как декодировать строку «url-encoded» в python
  • urllib.quote () бросает KeyError
  • urllib.urlencode не любит значения unicode: как об этом обходном пути?
  • Как индексировать URL-параметры в Python?
  • Как кодировать и декодировать строку с Python для использования в URL-адресе?
  • 7 Solutions collect form web for “urlencode многомерный словарь в python”

    Хорошо, люди. Я сам реализовал это:

     import urllib def recursive_urlencode(d): """URL-encode a multidimensional dictionary. >>> data = {'a': 'b&c', 'd': {'e': {'f&g': 'h*i'}}, 'j': 'k'} >>> recursive_urlencode(data) u'a=b%26c&j=k&d[e][f%26g]=h%2Ai' """ def recursion(d, base=[]): pairs = [] for key, value in d.items(): new_base = base + [key] if hasattr(value, 'values'): pairs += recursion(value, new_base) else: new_pair = None if len(new_base) > 1: first = urllib.quote(new_base.pop(0)) rest = map(lambda x: urllib.quote(x), new_base) new_pair = "%s[%s]=%s" % (first, ']['.join(rest), urllib.quote(unicode(value))) else: new_pair = "%s=%s" % (urllib.quote(unicode(key)), urllib.quote(unicode(value))) pairs.append(new_pair) return pairs return '&'.join(recursion(d)) if __name__ == "__main__": import doctest doctest.testmod() 

    Тем не менее, мне было бы интересно узнать, есть ли лучший способ сделать это. Я не могу поверить, что стандартная библиотека Python не реализует это.

    Что-то вроде этого?

     a = {'a': 'b', 'c': {'d': 'e'}} url = urllib.urlencode([('%s[%s]'%(k,v.keys()[0]), v.values()[0] ) if type(v)==dict else (k,v) for k,v in a.iteritems()]) url = 'a=b&c%5Bd%5D=e' 

    Вышеприведенное решение работает только для массивов с глубиной <2. Код ниже правильно задает многомерный массив любой глубины.

     #!/usr/bin/env python import sys import urllib def recursive_urlencode(data): def r_urlencode(data, parent=None, pairs=None): if pairs is None: pairs = {} if parent is None: parents = [] else: parents = parent for key, value in data.items(): if hasattr(value, 'values'): parents.append(key) r_urlencode(value, parents, pairs) parents.pop() else: pairs[renderKey(parents + [key])] = renderVal(value) return pairs return urllib.urlencode(r_urlencode(data)) def renderKey(parents): depth, outStr = 0, '' for x in parents: str = "[%s]" if depth > 0 else "%s" outStr += str % renderVal(x) depth += 1 return outStr def renderVal(val): return urllib.quote(unicode(val)) def main(): print recursive_urlencode(payload) if __name__ == '__main__': sys.exit(main()) 

    Основываясь на коде @malaney, я думаю, что приведенный ниже код очень хорошо эмулирует функцию PHP http_build_query() .

     #!/usr/bin/env python3 import urllib.parse def http_build_query(data): parents = list() pairs = dict() def renderKey(parents): depth, outStr = 0, '' for x in parents: s = "[%s]" if depth > 0 or isinstance(x, int) else "%s" outStr += s % str(x) depth += 1 return outStr def r_urlencode(data): if isinstance(data, list) or isinstance(data, tuple): for i in range(len(data)): parents.append(i) r_urlencode(data[i]) parents.pop() elif isinstance(data, dict): for key, value in data.items(): parents.append(key) r_urlencode(value) parents.pop() else: pairs[renderKey(parents)] = str(data) return pairs return urllib.parse.urlencode(r_urlencode(data)) if __name__ == '__main__': payload = { 'action': 'add', 'controller': 'invoice', 'code': 'debtor', 'InvoiceLines': [ {'PriceExcl': 150, 'Description': 'Setupfee'}, {'PriceExcl':49.99, 'Description':'Subscription'} ], 'date': '2016-08-01', 'key': 'Yikes&ampersand' } print(http_build_query(payload)) payload2 = [ 'item1', 'item2' ] print(http_build_query(payload2)) 

    как насчет json.dumps и json.loads?

     d = {'a': 'b', 'c': {'d': 'e'}} s = json.dumps(d) # s: '{"a": "b", "c": {"d": "e"}}' json.loads(s) # -> d 

    как насчет этой упрощенной версии:

     def _clean(value): return urllib.quote(unicode(value)) '&'.join([ v for val in [[ "%s[%s]=%s"%(k,ik, _(iv)) for ik, iv in v.items()] if type(v)==dict else ["%s=%s"%(k,_(v))] for k,v in data.items() ] for v in val ]) 

    Я согласен, не читаем, возможно, выравнивание списка может быть лучше сделано с помощью itertools.chain вместо другого понимания списка.

    Это будет только на 1 уровень глубже, ваш уровень может превышать N уровней, если вы добавите некоторую логику для управления N номерами «[% s]» в зависимости от уровня, но я думаю, это не так уж важно

    Я думаю, что код ниже может быть тем, что вы хотите

     импортировать urllib.parse
    
     def url_encoder (params):
         g_encode_params = {}
    
         def _encode_params (params, p_key = None):
             encode_params = {}
             if isststance (params, dict):
                 для ключа в параметрах:
                     encode_key = '{} [{}]'. format (p_key, key)
                     encode_params [encode_key] = params [key]
             elif isinstance (params, (list, tuple)):
                 для смещения, значение в перечислении (params):
                     encode_key = '{} [{}]'. format (p_key, offset)
                     encode_params [encode_key] = значение
             еще:
                 g_encode_params [p_key] = params
    
             для ключа в encode_params:
                 value = encode_params [key]
                 _encode_params (значение, ключ)
    
         if isststance (params, dict):
             для ключа в параметрах:
                 _encode_params (params [key], key)
    
         return urllib.parse.urlencode (g_encode_params)
    
     если __name__ == '__main__':
         params = {'name': 'interface_name', 'interfaces': [{'interface': 'inter1'}, {'interface': 'inter2'}]}
         печать (url_encoder (PARAMS)) 
    

    выход

     Интерфейсы% 5B1% 5D% 5Binterface% 5D = inter2 & имя = имя_интерфейс & интерфейсы% 5B0% 5D% 5Binterface% 5D = inter1
    

    который выглядит

     интерфейсы [1] [Интерфейс] = inter2 & имя = имя_интерфейс и интерфейсы [0] [Интерфейс] = inter1
    

    PS: вы можете использовать OrderDict для замены dict выше

    Python - лучший язык программирования в мире.