Python: convierte un complejo diccionario de cadenas de Unicode a ASCII

Posible duplicado:
¿Cómo obtener objetos de cadena en lugar de objetos Unicode de JSON en Python?

Tengo muchos datos de entrada como diccionarios de varios niveles analizados a partir de llamadas a la API JSON. Las cadenas están todas en Unicode, lo que significa que hay muchas u'stuff like this' . Estoy usando jq para jugar con los resultados y necesito convertir estos resultados a ASCII.

Sé que puedo escribir una función para convertirla así:

 def convert(input): if isinstance(input, dict): ret = {} for stuff in input: ret = convert(stuff) elif isinstance(input, list): ret = [] for i in range(len(input)) ret = convert(input[i]) elif isinstance(input, str): ret = input.encode('ascii') elif : ret = input return ret 

¿Es esto correcto? No es seguro. Eso no es lo que quiero preguntarte aunque.

Lo que pregunto es que esta es una solución típica de fuerza bruta para el problema. Tiene que haber una mejor manera. Una forma más pythonica. No soy un experto en algoritmos, pero este tampoco parece particularmente rápido.

Entonces, ¿hay una mejor manera? O si no, ¿puede mejorarse esta función …?


Edición post-respuesta

La respuesta de Mark Amery es correcta, pero me gustaría publicar una versión modificada. Su función funciona en Python 2.7+ y estoy en 2.6, así que tuve que convertirlo:

 def convert(input): if isinstance(input, dict): return dict((convert(key), convert(value)) for key, value in input.iteritems()) elif isinstance(input, list): return [convert(element) for element in input] elif isinstance(input, unicode): return input.encode('utf-8') else: return input 

La recursión parece ser el camino a seguir aquí, pero si está en Python 2.xx desea verificar unicode , no str (el tipo str representa una cadena de bytes, y el unicode escribe una cadena de caracteres unicode; se hereda de la otra y son cadenas de tipo Unicode que se muestran en el intérprete con au delante de ellas).

También hay un pequeño error de syntax en su código publicado (el elif: final elif: debería ser otra else ), y no está devolviendo la misma estructura en el caso de que la entrada sea un diccionario o una lista. (En el caso de un diccionario, está devolviendo la versión convertida de la clave final; en el caso de una lista, está devolviendo la versión convertida del elemento final. ¡Ninguno de los dos es correcto!)

También puede hacer que su código sea bonito y Pythonic utilizando las comprensiones.

Aquí, entonces, es lo que yo recomendaría:

 def convert(input): if isinstance(input, dict): return {convert(key): convert(value) for key, value in input.iteritems()} elif isinstance(input, list): return [convert(element) for element in input] elif isinstance(input, unicode): return input.encode('utf-8') else: return input 

Una última cosa. Cambié la encode('ascii') por la encode('utf-8') . Mi razonamiento es el siguiente: cualquier cadena Unicode que contenga solo caracteres en el conjunto de caracteres ASCII estará representada por la misma cadena de bytes cuando esté codificada en ASCII que cuando esté codificada en utf-8, por lo que usar utf-8 en lugar de ASCII no puede romper nada. el cambio será invisible siempre y cuando las cadenas Unicode con las que estás tratando utilicen solo caracteres ASCII. Sin embargo, este cambio amplía el scope de la función para poder manejar cadenas de caracteres de todo el conjunto de caracteres Unicode, en lugar de solo ASCII, en caso de que alguna vez sea necesario.