write utf8 una txt manejo linea leer lectura importar funcion especifica escritura como binarios archivos archivo acentos python json serialization unicode python-2.x

python - utf8 - ¿Cómo obtener objetos de cadena en lugar de Unicode desde JSON?



manejo de archivos binarios en python (21)

Estoy usando Python 2 para analizar JSON desde archivos de texto codificados ASCII .

Al cargar estos archivos con json o simplejson , todos mis valores de cadena se simplejson en objetos Unicode en lugar de objetos de cadena. El problema es que tengo que usar los datos con algunas bibliotecas que solo aceptan objetos de cadena. No puedo cambiar las bibliotecas ni actualizarlas.

¿Es posible obtener objetos de cadena en lugar de objetos Unicode?

Ejemplo

>>> import json >>> original_list = [''a'', ''b''] >>> json_list = json.dumps(original_list) >>> json_list ''["a", "b"]'' >>> new_list = json.loads(json_list) >>> new_list [u''a'', u''b''] # I want these to be of type `str`, not `unicode`

Actualizar

Esta pregunta se hizo hace mucho tiempo , cuando estaba atrapado con Python 2 . Una solución fácil y limpia para hoy es usar una versión reciente de Python, es decir, Python 3 y versiones posteriores.


Una solución con object_hook

import json def json_load_byteified(file_handle): return _byteify( json.load(file_handle, object_hook=_byteify), ignore_dicts=True ) def json_loads_byteified(json_text): return _byteify( json.loads(json_text, object_hook=_byteify), ignore_dicts=True ) def _byteify(data, ignore_dicts = False): # if this is a unicode string, return its string representation if isinstance(data, unicode): return data.encode(''utf-8'') # if this is a list of values, return list of byteified values if isinstance(data, list): return [ _byteify(item, ignore_dicts=True) for item in data ] # if this is a dictionary, return dictionary of byteified keys and values # but only if we haven''t already byteified it if isinstance(data, dict) and not ignore_dicts: return { _byteify(key, ignore_dicts=True): _byteify(value, ignore_dicts=True) for key, value in data.iteritems() } # if it''s anything else, return it in its original form return data

Ejemplo de uso:

>>> json_loads_byteified(''{"Hello": "World"}'') {''Hello'': ''World''} >>> json_loads_byteified(''"I am a top-level string"'') ''I am a top-level string'' >>> json_loads_byteified(''7'') 7 >>> json_loads_byteified(''["I am inside a list"]'') [''I am inside a list''] >>> json_loads_byteified(''[[[[[[[["I am inside a big nest of lists"]]]]]]]]'') [[[[[[[[''I am inside a big nest of lists'']]]]]]]] >>> json_loads_byteified(''{"foo": "bar", "things": [7, {"qux": "baz", "moo": {"cow": ["milk"]}}]}'') {''things'': [7, {''qux'': ''baz'', ''moo'': {''cow'': [''milk'']}}], ''foo'': ''bar''} >>> json_load_byteified(open(''somefile.json'')) {''more json'': ''from a file''}

¿Cómo funciona esto y por qué lo usaría?

La función de Mark Amery es más corta y clara que estas, ¿cuál es el punto de ellas? ¿Por qué querrías usarlos?

Puramente para el rendimiento . La respuesta de Mark descodifica el texto JSON completamente primero con cadenas Unicode, luego recurre a través de todo el valor descodificado para convertir todas las cadenas en cadenas de bytes. Esto tiene un par de efectos indeseables:

  • Una copia de toda la estructura decodificada se crea en la memoria
  • Si su objeto JSON está realmente anidado (500 niveles o más), entonces alcanzará la profundidad máxima de recursión de Python

Esta respuesta mitiga ambos problemas de rendimiento utilizando el parámetro json.load de json.load y json.loads . De la documentación :

object_hook es una función opcional que se llamará con el resultado de cualquier objeto decodificado literalmente (un dict ). El valor de retorno de object_hook se utilizará en lugar del dict . Esta característica se puede utilizar para implementar decodificadores personalizados

Dado que los diccionarios anidados en muchos niveles en otros diccionarios se pasan a object_hook medida que se decodifican , podemos byteificar cualquier cadena o lista dentro de ellos en ese momento y evitar la necesidad de recursión profunda más adelante.

La respuesta de Mark no es adecuada para su uso como object_hook tal como está, porque se repite en diccionarios anidados. ignore_dicts esa recursión en esta respuesta con el parámetro ignore_dicts a _byteify , que se le pasa en todo momento, excepto cuando object_hook pasa un nuevo dictado a byteify. La bandera ignore_dicts le dice a _byteify que ignore los dict s ya que ya fueron bytes.

Finalmente, nuestras implementaciones de json_load_byteified y json_loads_byteified llaman a _byteify (con ignore_dicts=True ) en el resultado devuelto por json.load o json.loads para manejar el caso en el que el texto JSON que se está descodificando no tiene un dict en el nivel superior.


Admite Python2 y 3 usando gancho (de https://.com/a/33571117/558397 )

import requests import six from six import iteritems requests.packages.urllib3.disable_warnings() # @UndefinedVariable r = requests.get("http://echo.jsontest.com/key/value/one/two/three", verify=False) def _byteify(data): # if this is a unicode string, return its string representation if isinstance(data, six.string_types): return str(data.encode(''utf-8'').decode()) # if this is a list of values, return list of byteified values if isinstance(data, list): return [ _byteify(item) for item in data ] # if this is a dictionary, return dictionary of byteified keys and values # but only if we haven''t already byteified it if isinstance(data, dict): return { _byteify(key): _byteify(value) for key, value in iteritems(data) } # if it''s anything else, return it in its original form return data w = r.json(object_hook=_byteify) print(w)

Devoluciones:

{''three'': '''', ''key'': ''value'', ''one'': ''two''}


Como señala Mark (Amery) correctamente: el uso del deserializador de PyYaml en un volcado json solo funciona si tiene ASCII solamente. Al menos fuera de la caja.

Dos comentarios rápidos sobre el enfoque PyYaml:

  1. NEVER use yaml.load en los datos del campo. Es una característica (!) De yaml para ejecutar código arbitrario oculto dentro de la estructura.

  2. Puede hacerlo funcionar también para no ASCII a través de esto:

    def to_utf8(loader, node): return loader.construct_scalar(node).encode(''utf-8'') yaml.add_constructor(u''tag:yaml.org,2002:str'', to_utf8)

Pero el rendimiento no tiene comparación con la respuesta de Mark Amery:

Al lanzar algunos ejemplos de ejemplos profundamente anidados en los dos métodos, obtengo esto (con dt [j] = tiempo delta de json.loads (json.dumps (m))):

dt[yaml.safe_load(json.dumps(m))] =~ 100 * dt[j] dt[byteify recursion(Mark Amery)] =~ 5 * dt[j]

Por lo tanto, la deserialización incluye caminar por el árbol y la codificación, dentro del orden de magnitud de la implementación basada en C de json. Encuentro esto notablemente rápido y también más robusto que la carga de yaml en estructuras profundamente anidadas. Y menos propenso a errores de seguridad, mirando yaml.load.

=> Aunque apreciaría un puntero a un convertidor basado únicamente en C, la función de byteify debería ser la respuesta predeterminada.

Esto es especialmente cierto si su estructura json es del campo y contiene información del usuario. Porque es probable que tenga que caminar de todos modos sobre su estructura, independientemente de las estructuras de datos internas que desee (''sándwich Unicode'' o solo cadenas de bytes).

¿Por qué?

Normalización Unicode. Para los que no lo saben: tomar un analgésico y leer this .

Entonces usando la recursión de byteify matas dos pájaros de un tiro:

  1. obtener sus bytestrings de volcados JSON anidados
  2. Obtenga valores de entrada de usuario normalizados, para que encuentre las cosas en su almacenamiento.

En mis pruebas, resultó que reemplazar el input.encode (''utf-8'') con unicodedata.normalize (''NFC'', input) .encode (''utf-8'') fue incluso más rápido que w / o NFC, pero eso es muy dependiente de los datos de la muestra, supongo.


El problema es que simplejson y json son dos módulos diferentes, al menos en la forma en que tratan con Unicode. Tienes json en py 2.6+, y esto te da valores Unicode, mientras que simplejson devuelve objetos de cadena. Solo intente easy_install-ing simplejson en su entorno y vea si funciona. Lo hizo por mí.


Esto es tarde para el juego, pero construí este lanzador recursivo. Funciona para mis necesidades y creo que es relativamente completo. Te puede ayudar.

def _parseJSON(self, obj): newobj = {} for key, value in obj.iteritems(): key = str(key) if isinstance(value, dict): newobj[key] = self._parseJSON(value) elif isinstance(value, list): if key not in newobj: newobj[key] = [] for i in value: newobj[key].append(self._parseJSON(i)) elif isinstance(value, unicode): val = str(value) if val.isdigit(): val = int(val) else: try: val = float(val) except ValueError: val = str(val) newobj[key] = val return newobj

Solo pásale un objeto JSON así:

obj = json.loads(content, parse_float=float, parse_int=int) obj = _parseJSON(obj)

Lo tengo como miembro privado de una clase, pero puede reutilizar el método como mejor le parezca.


Esto se debe a que json no tiene diferencia entre los objetos de cadena y los objetos Unicode. Son todas las cadenas en javascript.

Creo que JSON tiene razón al devolver objetos Unicode . De hecho, no aceptaría nada menos, ya que las cadenas javascript son de hecho objetos unicode (es decir, las cadenas JSON (javascript) pueden almacenar cualquier tipo de carácter Unicode), por lo que tiene sentido crear objetos unicode al traducir cadenas desde JSON. Las cadenas simples no encajarían ya que la biblioteca tendría que adivinar la codificación que desea.

Es mejor usar objetos de cadena unicode todas partes. Así que su mejor opción es actualizar sus bibliotecas para que puedan tratar con objetos Unicode.

Pero si realmente quiere secuencias de bytes, simplemente codifique los resultados a la codificación de su elección:

>>> nl = json.loads(js) >>> nl [u''a'', u''b''] >>> nl = [s.encode(''utf-8'') for s in nl] >>> nl [''a'', ''b'']


Existe una solución fácil.

TL; DR: use ast.literal_eval() lugar de json.loads() . Tanto ast como json están en la biblioteca estándar.

Si bien no es una respuesta "perfecta", llega bastante lejos si su plan es ignorar por completo a Unicode. En Python 2.7

import json, ast d = { ''field'' : ''value'' } print "JSON Fail: ", json.loads(json.dumps(d)) print "AST Win:", ast.literal_eval(json.dumps(d))

da:

JSON Fail: {u''field'': u''value''} AST Win: {''field'': ''value''}

Esto se vuelve más peludo cuando algunos objetos son realmente cuerdas Unicode. La respuesta completa se vuelve peluda rápidamente.


Me temo que no hay forma de lograr esto automáticamente dentro de la biblioteca simplejson.

El escáner y el decodificador en simplejson están diseñados para producir texto Unicode. Para hacer esto, la biblioteca usa una función llamada c_scanstring (si está disponible, por velocidad), o py_scanstring si la versión C no está disponible. La función scanstring es llamada varias veces por casi todas las rutinas que tiene simplejson para descodificar una estructura que puede contener texto. Tendría que ajustar el valor de la cadena de exploración en simplejson.decoder o la subclase JSONDecoder y proporcionar prácticamente toda su implementación completa de cualquier cosa que pueda contener texto.

Sin embargo, la razón por la que simplejson genera unicode es que la especificación json menciona específicamente que "Una cadena es una colección de cero o más caracteres Unicode" ... el soporte para Unicode se asume como parte del formato en sí. La implementación de la cadena de exploración de scanstring va tan lejos como para escanear e interpretar escapes de Unicode (incluso la comprobación de errores para las representaciones de conjuntos de caracteres de múltiples bytes mal formados), por lo que la única forma en que puede devolverle el valor de manera confiable es como unicode.

Si tiene una biblioteca antigua que necesita una str , le recomiendo que busque laboriosamente la estructura de datos anidada después de analizar (lo que reconozco es lo que dijo explícitamente que quería evitar ... lo siento), o tal vez envuelva sus bibliotecas de alguna manera. de fachada donde puede masajear los parámetros de entrada a un nivel más granular. El segundo enfoque podría ser más manejable que el primero si sus estructuras de datos están profundamente anidadas.


No hay una opción incorporada para hacer que las funciones del módulo json devuelvan cadenas de bytes en lugar de cadenas Unicode. Sin embargo, esta función recursiva corta y simple convertirá cualquier objeto JSON descodificado de usar cadenas Unicode a cadenas de bytes codificadas en UTF-8:

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

Simplemente llame a esto en la salida que obtiene de una llamada json.load o json.loads .

Un par de notas:

  • Para admitir Python 2.6 o anterior, reemplace return {byteify(key): byteify(value) for key, value in input.iteritems()} con return dict([(byteify(key), byteify(value)) for key, value in input.iteritems()]) , ya que las comprensiones del diccionario no fueron compatibles hasta Python 2.7
  • Dado que esta respuesta recurre a través de todo el objeto descodificado, tiene un par de características de rendimiento indeseables que se pueden evitar con un uso muy cuidadoso de los parámetros object_hook o object_pairs_hook . La respuesta de Mirec Miskuf es hasta ahora la única que logra llevar a cabo esto correctamente, aunque como consecuencia, es significativamente más complicada que mi enfoque.

Por lo tanto, me he encontrado con el mismo problema. Adivina cual fue el primer resultado de Google.

Como necesito pasar todos los datos a PyGTK, las cadenas Unicode tampoco son muy útiles para mí. Así que tengo otro método de conversión recursiva. En realidad, también es necesario para la conversión JSON a prueba de tipos: json.dump () se liberaría de cualquier no-literales, como los objetos Python. Sin embargo, no convierte los índices de dict.

# removes any objects, turns unicode back into str def filter_data(obj): if type(obj) in (int, float, str, bool): return obj elif type(obj) == unicode: return str(obj) elif type(obj) in (list, tuple, set): obj = list(obj) for i,v in enumerate(obj): obj[i] = filter_data(v) elif type(obj) == dict: for i,v in obj.iteritems(): obj[i] = filter_data(v) else: print "invalid object in data, converting to string" obj = str(obj) return obj


Puede usar el parámetro object_hook para que json.loads pase un convertidor. No tienes que hacer la conversión después del hecho. El módulo json siempre pasará solo los object_hook object_hook, y pasará recursivamente en dicts anidados, por lo que no tiene que recurrir a dicts anidados usted mismo. No creo que convierta las cadenas Unicode en números como los de Wells. Si se trata de una cadena Unicode, se citó como una cadena en el archivo JSON, por lo que se supone que es una cadena (o el archivo es malo).

Además, trataría de evitar hacer algo como str(val) en un objeto unicode . Debe usar value.encode(encoding) con una codificación válida, dependiendo de lo que espere su lib externo.

Así por ejemplo:

def _decode_list(data): rv = [] for item in data: if isinstance(item, unicode): item = item.encode(''utf-8'') elif isinstance(item, list): item = _decode_list(item) elif isinstance(item, dict): item = _decode_dict(item) rv.append(item) return rv def _decode_dict(data): rv = {} for key, value in data.iteritems(): if isinstance(key, unicode): key = key.encode(''utf-8'') if isinstance(value, unicode): value = value.encode(''utf-8'') elif isinstance(value, list): value = _decode_list(value) elif isinstance(value, dict): value = _decode_dict(value) rv[key] = value return rv obj = json.loads(s, object_hook=_decode_dict)


Si bien hay algunas respuestas buenas aquí, terminé usando PyYAML para analizar mis archivos JSON, ya que proporciona las claves y los valores como cadenas de tipo str lugar de tipo unicode . Como JSON es un subconjunto de YAML, funciona muy bien:

>>> import json >>> import yaml >>> list_org = [''a'', ''b''] >>> list_dump = json.dumps(list_org) >>> list_dump ''["a", "b"]'' >>> json.loads(list_dump) [u''a'', u''b''] >>> yaml.safe_load(list_dump) [''a'', ''b'']

Notas

Algunas cosas a tener en cuenta sin embargo:

  • Obtengo objetos de cadena porque todas mis entradas están codificadas en ASCII . Si usara entradas codificadas en Unicode, las recuperaría como objetos Unicode , ¡no hay conversión!

  • Debería (probablemente siempre) usar la función safe_load de safe_load ; si lo usa para cargar archivos JSON, de todos modos no necesita la "potencia adicional" de la función de load .

  • Si desea un analizador YAML que tenga más soporte para la versión 1.2 de la especificación (y analice correctamente los números muy bajos ) intente con Ruamel YAML : pip install ruamel.yaml e import ruamel.yaml as yaml era todo lo que necesitaba en mis pruebas.

Conversión

Como se dijo, no hay conversión! Si no puede estar seguro de tratar solo con los valores ASCII (y no puede estar seguro la mayor parte del tiempo), utilice mejor una función de conversión :

Usé el de Mark Amery un par de veces, funciona muy bien y es muy fácil de usar. También puede usar una función similar como object_hook en object_hook lugar, ya que podría obtener un aumento de rendimiento en archivos grandes. Vea la respuesta un poco más complicada de Mirec Miskuf para eso.


Solo use pickle en lugar de json para volcar y cargar, así:

import json import pickle d = { ''field1'': ''value1'', ''field2'': 2, } json.dump(d,open("testjson.txt","w")) print json.load(open("testjson.txt","r")) pickle.dump(d,open("testpickle.txt","w")) print pickle.load(open("testpickle.txt","r"))

La salida que produce es (las cadenas y los enteros se manejan correctamente):

{u''field2'': 2, u''field1'': u''value1''} {''field2'': 2, ''field1'': ''value1''}


La respuesta de Mike Brennan es cercana, pero no hay razón para volver a atravesar toda la estructura. Si usa el object_hook_pairs (Python 2.7+):

object_pairs_hook es una función opcional que se llamará con el resultado de cualquier objeto decodificado literalmente con una lista ordenada de pares. El valor de retorno de object_pairs_hook se utilizará en lugar del dict . Esta función se puede usar para implementar decodificadores personalizados que dependen del orden en que se decodifican los pares de clave y valor (por ejemplo, collections.OrderedDict OrderedDict recordará el orden de inserción). Si también se define object_pairs_hook , object_pairs_hook tiene prioridad.

Con él, obtienes cada objeto JSON entregado, por lo que puedes hacer la decodificación sin necesidad de recursión:

def deunicodify_hook(pairs): new_pairs = [] for key, value in pairs: if isinstance(value, unicode): value = value.encode(''utf-8'') if isinstance(key, unicode): key = key.encode(''utf-8'') new_pairs.append((key, value)) return dict(new_pairs) In [52]: open(''test.json'').read() Out[52]: ''{"1": "hello", "abc": [1, 2, 3], "def": {"hi": "mom"}, "boo": [1, "hi", "moo", {"5": "some"}]}'' In [53]: json.load(open(''test.json'')) Out[53]: {u''1'': u''hello'', u''abc'': [1, 2, 3], u''boo'': [1, u''hi'', u''moo'', {u''5'': u''some''}], u''def'': {u''hi'': u''mom''}} In [54]: json.load(open(''test.json''), object_pairs_hook=deunicodify_hook) Out[54]: {''1'': ''hello'', ''abc'': [1, 2, 3], ''boo'': [1, ''hi'', ''moo'', {''5'': ''some''}], ''def'': {''hi'': ''mom''}}

Tenga en cuenta que nunca tengo que llamar al gancho de forma recursiva ya que cada objeto se entregará al gancho cuando use el object_pairs_hook . Usted tiene que preocuparse por las listas, pero como puede ver, un objeto dentro de una lista se convertirá correctamente, y no tiene que repetir para hacer que suceda.

EDITAR: un compañero de trabajo señaló que Python2.6 no tiene object_hook_pairs . Aún puedes usar este Python2.6 haciendo un cambio muy pequeño. En el gancho de arriba, cambia:

for key, value in pairs:

a

for key, value in pairs.iteritems():

Luego use object_hook lugar de object_pairs_hook :

In [66]: json.load(open(''test.json''), object_hook=deunicodify_hook) Out[66]: {''1'': ''hello'', ''abc'': [1, 2, 3], ''boo'': [1, ''hi'', ''moo'', {''5'': ''some''}], ''def'': {''hi'': ''mom''}}

El uso de object_pairs_hook da object_pairs_hook resultado que se object_pairs_hook una instancia de un diccionario menos para cada objeto en el objeto JSON, que, si estuviera analizando un gran documento, podría valer la pena.


Reescribí _parse_json () de Wells para manejar casos en los que el objeto json en sí es una matriz (mi caso de uso).

def _parseJSON(self, obj): if isinstance(obj, dict): newobj = {} for key, value in obj.iteritems(): key = str(key) newobj[key] = self._parseJSON(value) elif isinstance(obj, list): newobj = [] for value in obj: newobj.append(self._parseJSON(value)) elif isinstance(obj, unicode): newobj = str(obj) else: newobj = obj return newobj


Aquí hay un codificador recursivo escrito en C: https://github.com/axiros/nested_encode

Gastos generales de rendimiento para estructuras "promedio" en torno al 10% en comparación con json.loads.

python speed.py json loads [0.16sec]: {u''a'': [{u''b'': [[1, 2, [u''/xd6ster.. json loads + encoding [0.18sec]: {''a'': [{''b'': [[1, 2, [''/xc3/x96ster. time overhead in percent: 9%

utilizando esta estructura de prueba:

import json, nested_encode, time s = """ { "firstName": "Jos//u0301", "lastName": "Smith", "isAlive": true, "age": 25, "address": { "streetAddress": "21 2nd Street", "city": "//u00d6sterreich", "state": "NY", "postalCode": "10021-3100" }, "phoneNumbers": [ { "type": "home", "number": "212 555-1234" }, { "type": "office", "number": "646 555-4567" } ], "children": [], "spouse": null, "a": [{"b": [[1, 2, ["//u00d6sterreich"]]]}] } """ t1 = time.time() for i in xrange(10000): u = json.loads(s) dt_json = time.time() - t1 t1 = time.time() for i in xrange(10000): b = nested_encode.encode_nested(json.loads(s)) dt_json_enc = time.time() - t1 print "json loads [%.2fsec]: %s..." % (dt_json, str(u)[:20]) print "json loads + encoding [%.2fsec]: %s..." % (dt_json_enc, str(b)[:20]) print "time overhead in percent: %i%%" % (100 * (dt_json_enc - dt_json)/dt_json)


Con Python 3.6, a veces todavía me encuentro con este problema. Por ejemplo, al obtener la respuesta de una API REST y al cargar el texto de respuesta en JSON, todavía obtengo las cadenas Unicode. Encontré una solución simple usando json.dumps ().

response_message = json.loads(json.dumps(response.text)) print(response_message)


Echa un vistazo a this respuesta a una pregunta similar como esta que dice que

El prefijo u solo significa que tienes una cadena Unicode. Cuando realmente usa la cadena, no aparecerá en sus datos. No te eches por la salida impresa.

Por ejemplo, prueba esto:

print mail_accounts[0]["i"]

No verás una u.


He adaptado el código de la answer de Mark Amery , particularmente para deshacerme de isinstancelos profesionales de la tipificación de patos.

La codificación se realiza manualmente y ensure_asciise desactiva. La documentación de python json.dumpdice que

Si asegurar_ascii es Verdadero (el predeterminado), todos los caracteres no ASCII en la salida se escapan con secuencias / uXXXX

Descargo de responsabilidad: en el doctest utilicé el idioma húngaro. Algunas codificaciones de caracteres húngaras notables son: cp852la codificación IBM / OEM utilizada, por ejemplo. en DOS (a veces referido como ascii , creo que incorrectamente, depende de la configuración de la página de códigos ), cp1250utilizado por ejemplo. en Windows (a veces denominado ansi , dependiendo de la configuración regional) y iso-8859-2, a veces, se utiliza en servidores http. El texto de la prueba Tüskéshátú kígyóbűvölőse atribuye a Koltai László (forma de nombre personal nativo) y es de wikipedia .

# coding: utf-8 """ This file should be encoded correctly with utf-8. """ import json def encode_items(input, encoding=''utf-8''): u"""original from: https://.com/a/13101776/611007 adapted by SO/u/611007 (20150623) >>> >>> ## run this with `python -m doctest <this file>.py` from command line >>> >>> txt = u"Tüskéshátú kígyóbűvölő" >>> txt2 = u"T//u00fcsk//u00e9sh//u00e1t//u00fa k//u00edgy//u00f3b//u0171v//u00f6l//u0151" >>> txt3 = u"uúuutifu" >>> txt4 = b''u//xfauutifu'' >>> # txt4 shouldn''t be ''u//xc3//xbauutifu'', string content needs double backslash for doctest: >>> assert u''//u0102'' not in b''u//xfauutifu''.decode(''cp1250'') >>> txt4u = txt4.decode(''cp1250'') >>> assert txt4u == u''u//xfauutifu'', repr(txt4u) >>> txt5 = b"u//xc3//xbauutifu" >>> txt5u = txt5.decode(''utf-8'') >>> txt6 = u"u//u251c//u2551uutifu" >>> there_and_back_again = lambda t: encode_items(t, encoding=''utf-8'').decode(''utf-8'') >>> assert txt == there_and_back_again(txt) >>> assert txt == there_and_back_again(txt2) >>> assert txt3 == there_and_back_again(txt3) >>> assert txt3.encode(''cp852'') == there_and_back_again(txt4u).encode(''cp852'') >>> assert txt3 == txt4u,(txt3,txt4u) >>> assert txt3 == there_and_back_again(txt5) >>> assert txt3 == there_and_back_again(txt5u) >>> assert txt3 == there_and_back_again(txt4u) >>> assert txt3.encode(''cp1250'') == encode_items(txt4, encoding=''utf-8'') >>> assert txt3.encode(''utf-8'') == encode_items(txt5, encoding=''utf-8'') >>> assert txt2.encode(''utf-8'') == encode_items(txt, encoding=''utf-8'') >>> assert {''a'':txt2.encode(''utf-8'')} == encode_items({''a'':txt}, encoding=''utf-8'') >>> assert [txt2.encode(''utf-8'')] == encode_items([txt], encoding=''utf-8'') >>> assert [[txt2.encode(''utf-8'')]] == encode_items([[txt]], encoding=''utf-8'') >>> assert [{''a'':txt2.encode(''utf-8'')}] == encode_items([{''a'':txt}], encoding=''utf-8'') >>> assert {''b'':{''a'':txt2.encode(''utf-8'')}} == encode_items({''b'':{''a'':txt}}, encoding=''utf-8'') """ try: input.iteritems return {encode_items(k): encode_items(v) for (k,v) in input.iteritems()} except AttributeError: if isinstance(input, unicode): return input.encode(encoding) elif isinstance(input, str): return input try: iter(input) return [encode_items(e) for e in input] except TypeError: return input def alt_dumps(obj, **kwargs): """ >>> alt_dumps({''a'': u"T//u00fcsk//u00e9sh//u00e1t//u00fa k//u00edgy//u00f3b//u0171v//u00f6l//u0151"}) ''{"a": "T//xc3//xbcsk//xc3//xa9sh//xc3//xa1t//xc3//xba k//xc3//xadgy//xc3//xb3b//xc5//xb1v//xc3//xb6l//xc5//x91"}'' """ if ''ensure_ascii'' in kwargs: del kwargs[''ensure_ascii''] return json.dumps(encode_items(obj), ensure_ascii=False, **kwargs)

También me gustaría resaltar la answer de que hace referencia a la especificación JSON , citando:

Una cadena es una colección de cero o más caracteres Unicode

En mi caso de uso tuve archivos con json. Son utf-8archivos codificados. ensure_asciida como resultado archivos json que se han escapado correctamente pero no son muy legibles, por eso adapté la respuesta de Mark Amery para que se ajuste a mis necesidades.

El doctest no es particularmente atento, pero comparto el código con la esperanza de que sea útil para alguien.


Me encontré con este problema también, y al tener que lidiar con JSON, se me ocurrió un pequeño bucle que convierte las claves Unicode en cadenas. ( simplejsonen GAE no devuelve claves de cadena.)

obj es el objeto decodificado de JSON:

if NAME_CLASS_MAP.has_key(cls): kwargs = {} for i in obj.keys(): kwargs[str(i)] = obj[i] o = NAME_CLASS_MAP[cls](**kwargs) o.save()

kwargses lo que paso al constructor de la aplicación GAE (a la que no le gustan las unicodeclaves **kwargs)

No tan robusta como la solución de Wells, pero mucho más pequeña.


Tenía un dict de JSON como una cadena. Las claves y los valores eran objetos Unicode como en el siguiente ejemplo:

myStringDict = "{u''key'':u''value''}"

Podría usar la byteifyfunción sugerida anteriormente convirtiendo la cadena en un dictobjeto usando ast.literal_eval(myStringDict).