web-dev-qa-db-fra.com

Le moyen le plus rapide de convertir les clés et les valeurs d'un dict de `octets` en` str` en python3

Excellent exemple pour python2 ici . Ma traduction en python3 (illustrée ci-dessous) fonctionne dans tous mes tests.

def convert(data):
    if isinstance(data, bytes):
        return data.decode('ascii')
    Elif isinstance(data, dict):
        return dict(map(convert, data.items()))
    Elif isinstance(data, Tuple):
        return map(convert, data)
    else:
        return data

On dirait que j'utilise beaucoup cela pour des bibliothèques qui ont été portées de py2 à py3.

Quelqu'un at-il une meilleure conception pour la même tâche? Celui-ci pourrait-il être optimisé?

15
Guy Gangemi

Je ne sais pas pour l'optimisation de la vitesse mais je suis pas un grand fan de if/return/else paradigme car il obstrue le code avec des trucs inutiles et provoque des escaliers d'indentation pour les langues sans Elif (ce n'est pas un problème ici).

En optimisant pour lisibilité (qui est généralement ma première préférence), je transformerais toutes ces lignes Elif en if et abandonnerais complètement le else, reformatage pour le rendre plus compact:

def convert(data):
    if isinstance(data, bytes):  return data.decode('ascii')
    if isinstance(data, dict):   return dict(map(convert, data.items()))
    if isinstance(data, Tuple):  return map(convert, data)
    return data
16
paxdiablo

L'extension de la réponse de paxdiablo pour gérer plus de cas d'utilisation a donné les résultats suivants:

def convert(data):
  if isinstance(data, bytes):      return data.decode()
  if isinstance(data, (str, int)): return str(data)
  if isinstance(data, dict):       return dict(map(convert, data.items()))
  if isinstance(data, Tuple):      return Tuple(map(convert, data))
  if isinstance(data, list):       return list(map(convert, data))
  if isinstance(data, set):        return set(map(convert, data))

Il devient clair que l'application de la fonction de carte est assez cohérente et nous pouvons la généraliser.

def convert(data):
  data_type = type(data)

  if data_type == bytes: return data.decode()
  if data_type in (str, int): return str(data)

  if data_type == dict: data = data.items()
  return data_type(map(convert, data))
8
Guy Gangemi

Le moyen le plus simple serait d'utiliser la compréhension du dictionnaire comme suit:

new_data = { key.decode(): val.decode() for key, val in data.items() }

Exemple:

>>> data = {
...   b'cart1': b'apples',
...   b'cart2': b'oranges',
...   b'cart3': b'grapes'
... }
>>> 
>>> new_data = { key.decode(): val.decode() for key, val in data.items() }
>>> 
>>> new_data
{'cart1': 'apples', 'cart2': 'oranges', 'cart3': 'grapes'}
>>>

Pour convertir des paires de valeurs de clés d'octets de type dans un ordre aléatoire, utilisez:

new_data = {
    key.decode() if isinstance(key, bytes) else key:
    val.decode() if isinstance(val, bytes) else val
    for key, val in data.items()
}

Exemple:

>>> data = {
...   b'cart1': 'apples',
...   'cart2': b'oranges',
...   b'cart3': b'grapes'
... }
>>> 
>>> new_data = {
...     key.decode() if isinstance(key, bytes) else key:
...     val.decode() if isinstance(val, bytes) else val
...     for key, val in data.items()
... }
>>> new_data
{'cart1': 'apples', 'cart2': 'oranges', 'cart3': 'grapes'}
>>>

Remarque: Le code ci-dessus sera meilleur pour un dictionnaire de données simple. Mais pour les dictionnaires complexes, je préférerais utiliser le code de Guy Gangemi qui est une modification de paxdiablo réponse:

def convert(data):
    if isinstance(data, bytes):  return data.decode()
    if isinstance(data, dict):   return dict(map(convert, data.items()))
    if isinstance(data, Tuple):  return Tuple(map(convert, data))
    if isinstance(data, list):   return list(map(convert, data))
    return data

Exemple:

>>> 
>>> def convert(data):
...     if isinstance(data, bytes):  return data.decode()
...     if isinstance(data, dict):   return dict(map(convert, data.items()))
...     if isinstance(data, Tuple):  return Tuple(map(convert, data))
...     if isinstance(data, list):   return list(map(convert, data))
...     return data
...
>>>
>>> data = {
...     b'fruits': {
...             b'cart1': b'apples',
...             b'cart2': 'oranges',
...             b'cart3': b'grapes',
...             b'cart4': (b'banana', 'pear'),
...             b'cart5': [b'kiwi', b'papaya']
...     },
...     'vegetables': {
...             'cart1': b'carrots',
...             b'cart2': None,
...             b'cart3': {},
...             b'cart4': False
...     }
... }
>>>
>>> convert(data)
{'fruits': {'cart1': 'apples', 'cart2': 'oranges', 'cart3': 'grapes', 'cart4': ('banana', 'pear'), 'cart5': ['kiwi', 'papaya']}, 'vegetables': {'cart1': 'carrots', 'cart2': None, 'cart3': {}, 'cart4': False}}
>>>
5
jophine