Wie bekomme ich String-Objekte anstelle von Unicode von JSON?

276

Ich verwende Python 2 , um JSON aus ASCII-codierten Textdateien zu analysieren .

Beim Laden dieser Dateien mit entweder jsonoder simplejsonwerden alle meine Zeichenfolgenwerte in Unicode-Objekte anstelle von Zeichenfolgenobjekten umgewandelt. Das Problem ist, ich muss die Daten mit einigen Bibliotheken verwenden, die nur Zeichenfolgenobjekte akzeptieren. Ich kann die Bibliotheken weder ändern noch aktualisieren.

Ist es möglich, String-Objekte anstelle von Unicode-Objekten abzurufen?

Beispiel

>>> 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`

Aktualisieren

Diese Frage wurde vor langer Zeit gestellt , als ich mit Python 2 feststeckte . Eine einfache und saubere Lösung für heute ist die Verwendung einer aktuellen Version von Python - dh Python 3 und höher.

Brutus
quelle
1
Es gibt kein Problem unter Python3, die Art der Elemente in new_list iststr
GoingMyWay
1
Python 3k ist keine 'aktuelle Version von Python', sondern nur ein alternativer Zweig.
user2589273
11
Es ist seltsam, einen solchen Kommentar im Dezember 2017 zu sehen - Python 2 ist veraltet und nach dem 1. Januar 2020, der weniger als 2 Jahre dauert
Zaar Hai
1
@ZaarHai Viele Leute stecken gegen ihren Willen in Python 2 fest. Es gibt viele Anwendungen, die ihre eigene Python-Version für die Automatisierung und Skripterstellung einbetten, sodass die Benutzer sie verwenden müssen, bis der Anbieter aktualisiert ist (ich sehe Sie an, Maya, Houdini, Nuke ..)
Geordie
1
@Geordie Das weiß und verstehe ich sicher. Mein Kommentar betraf die Terminologie - Python ist kein "alternativer Zweig", sondern ein unglücklicher Mangel an Alternative (Wortspiel beabsichtigt) für diejenigen, die daran festhalten.
Zaar Hai

Antworten:

101

Eine Lösung mit 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

Anwendungsbeispiel:

>>> 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'}

Wie funktioniert das und warum sollte ich es verwenden?

Mark Amerys Funktion ist kürzer und klarer als diese. Worum geht es also? Warum sollten Sie sie verwenden wollen?

Nur für die Leistung . Marks Antwort dekodiert den JSON-Text zuerst vollständig mit Unicode-Zeichenfolgen und rekursiert dann den gesamten dekodierten Wert, um alle Zeichenfolgen in Byte-Zeichenfolgen zu konvertieren. Dies hat einige unerwünschte Auswirkungen:

  • Eine Kopie der gesamten dekodierten Struktur wird im Speicher erstellt
  • Wenn Ihr JSON-Objekt wirklich tief verschachtelt ist (500 Ebenen oder mehr), erreichen Sie die maximale Rekursionstiefe von Python

Diese Antwort verringert diese beiden Leistungsprobleme mithilfe des object_hookParameters json.loadund json.loads. Aus den Dokumenten :

object_hookist eine optionale Funktion, die mit dem Ergebnis eines dekodierten Objektliteral (a dict) aufgerufen wird . Der Rückgabewert von object_hook wird anstelle von verwendet dict. Mit dieser Funktion können benutzerdefinierte Decoder implementiert werden

Da Wörterbücher, die viele Ebenen tief in anderen Wörterbüchern verschachtelt object_hook sind, beim Dekodieren übergeben werden , können wir an dieser Stelle alle darin enthaltenen Zeichenfolgen oder Listen byteifizieren und später die Notwendigkeit einer tiefen Rekursion vermeiden.

Marks Antwort ist nicht für die Verwendung object_hookin der jetzigen Form geeignet , da sie in verschachtelte Wörterbücher zurückgeführt wird. Wir verhindern , dass die Rekursion in dieser Antwort mit dem ignore_dictsParameter auf _byteify, die jederzeit an sie übergeben wird , außer wenn object_hookübergibt sie ein neues dictbyteify. Das ignore_dictsFlag weist _byteifyan, dicts zu ignorieren, da sie bereits byteifiziert wurden.

Schließlich haben unsere Implementierungen von json_load_byteifiedund json_loads_byteifiedrufen _byteify(mit ignore_dicts=True) das Ergebnis auf, das von json.loadoder zurückgegeben wurde json.loads, um den Fall zu behandeln, in dem der zu dekodierende JSON-Text kein dictoberstes Element hat.

Mirec Miskuf
quelle
1
+1 für den Ansatz hier; Ich habe es nicht wirklich verstanden, als ich es zum ersten Mal las, aber schließlich verstanden, als ich es im Lichte von Travis Jensens Antwort noch einmal las. Ich habe eine ziemlich aggressive Bearbeitung vorgenommen, in der Hoffnung zu klären, wie es funktioniert und welche Vorteile es gegenüber meiner Antwort hat. Die Kernidee des Codes bleibt unberührt, aber ich habe so ziemlich alles andere geändert. Fühlen Sie sich frei, meine Bearbeitung zurückzusetzen, wenn Sie dagegen sind - es ist Ihre Antwort!
Mark Amery
Kein Problem Mark, vielen Dank. Ich mag deine Bearbeitung, sie ist viel erklärender als mein Original. Vielleicht werde ich eines Tages lernen, präzisere Antworten zu geben.
Mirec Miskuf
2
Das ist eine großartige Lösung. effizient und elegant. Wenn Sie jedoch wie ich im Bereich von Python <2.7 stecken bleiben, müssen Sie die Zeile ersetzen: return { byteify(key, ignore_dicts=True): _byteify(value, ignore_dicts=True) for key, value in data.iteritems() }durch, return dict((_byteify(key, ignore_dicts=True), _byteify(value, ignore_dicts=True)) for key, value in data.iteritems())damit sie funktioniert.
Richard Dunn
Ich denke, Sie irren sich in Bezug auf das Problem der Rekursionstiefe. Mit deiner kann ich bis zu 990 gehen : json_loads_byteified('[' * 990 + ']' * 990). Mit 991 stürzt es ab. Marks arbeitet immer noch mit 991 : byteify(json.loads('[' * 991 + ']' * 991)). Es stürzt bei 992 ab. Zumindest in diesem Test kann Marks tiefer gehen, im Gegensatz zu dem, was Sie gesagt haben.
Stefan Pochmann
@ MarkAmery Was denkst du über meinen obigen Kommentar? (Ich habe gerade in der Bearbeitungshistorie gesehen, dass Sie es tatsächlich waren, die diese Behauptung hinzugefügt haben).
Stefan Pochmann
180

Obwohl es hier einige gute Antworten gibt, habe ich PyYAML zum Parsen meiner JSON-Dateien verwendet, da die Schlüssel und Werte als Typzeichenfolgenstr anstelle von unicodeTyp angegeben werden. Da JSON eine Teilmenge von YAML ist, funktioniert es gut:

>>> 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']

Anmerkungen

Einige Dinge zu beachten:

  • Ich erhalte Zeichenfolgenobjekte, da alle meine Einträge ASCII-codiert sind . Wenn ich Unicode-codierte Einträge verwenden würde, würde ich sie als Unicode-Objekte zurückerhalten - es gibt keine Konvertierung!

  • Sie sollten (wahrscheinlich immer) die PyYAML- safe_loadFunktion verwenden. Wenn Sie damit JSON-Dateien laden, benötigen Sie loadohnehin nicht die "zusätzliche Leistung" der Funktion.

  • Wenn Sie einen YAML-Parser möchten, der die 1.2-Version der Spezifikation besser unterstützt (und sehr niedrige Zahlen korrekt analysiert ), versuchen Sie es mit Ruamel YAML : pip install ruamel.yamlund das import ruamel.yaml as yamlwar alles, was ich für meine Tests brauchte.

Umwandlung

Wie gesagt, es gibt keine Konvertierung! Wenn Sie nicht sicher sein können, nur mit ASCII-Werten umzugehen (und Sie können die meiste Zeit nicht sicher sein), verwenden Sie besser eine Konvertierungsfunktion :

Ich habe das von Mark Amery jetzt ein paar Mal benutzt, es funktioniert großartig und ist sehr einfach zu bedienen. Sie können object_hookstattdessen auch eine ähnliche Funktion verwenden, da dies zu einer Leistungssteigerung bei großen Dateien führen kann. Siehe dazu die etwas aufwendigere Antwort von Mirec Miskuf .

Brutus
quelle
8
Seien Sie vorsichtig, wenn Sie diese Antwort verwenden möchten. Es funktioniert perfekt für Brutus 'Fall, aber nur, weil er weiß, dass seine Daten nur ASCII-codierbare Zeichen enthalten. Wenn Sie diese Garantie nicht haben, funktioniert diese Antwort nicht. Versuchen Sie beispielsweise, yaml.load(json.dumps([u'a', u'£', u'É']))die Python-Shell auszuführen, und stellen Sie fest, dass Sie zurückkehren ['a', u'\xa3', u'\xc9'](die unicodeZeichenfolgen enthält ). Wenn Sie nicht sicher sein können, dass Ihre Daten nur Zeichen aus dem ASCII-Zeichensatz enthalten, sollten Sie stattdessen einen anderen Ansatz verwenden (ich empfehle meine eigene Antwort).
Mark Amery
1
YAML ist auch [u'a', u'b']vorsichtig.
Carlos Calla
1
Das ist schön, aber es funktioniert nicht mit niedrigen Zahlen. Schauen Sie hier: stackoverflow.com/questions/30458977/…
Oren
@Oren: Dies ist kein Fehler in der YAML-Spezifikation, sondern im PyYAML-Parser. Der YAML-Parser von Ruamel funktioniert.
Brutus
Ich möchte eine Ausgabe wie ["a", "b"] haben, nicht wie ['a', 'b'] @Brutus
user60679
141

Es gibt keine integrierte Option, mit der die Funktionen des JSON-Moduls Byte-Zeichenfolgen anstelle von Unicode-Zeichenfolgen zurückgeben. Diese kurze und einfache rekursive Funktion konvertiert jedoch jedes dekodierte JSON-Objekt von der Verwendung von Unicode-Zeichenfolgen in UTF-8-codierte Byte-Zeichenfolgen:

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

Rufen Sie dies einfach an der Ausgabe auf, die Sie von einem json.loadoder einem json.loadsAnruf erhalten.

Ein paar Anmerkungen:

  • Um Python 2.6 oder früher zu unterstützen, ersetzen Sie return {byteify(key): byteify(value) for key, value in input.iteritems()}durch return dict([(byteify(key), byteify(value)) for key, value in input.iteritems()]), da das Wörterbuchverständnis erst mit Python 2.7 unterstützt wurde.
  • Da diese Antwort durch das gesamte decodierte Objekt wiederholt wird, weist sie einige unerwünschte Leistungsmerkmale auf, die durch sehr sorgfältige Verwendung der Parameter object_hookoder vermieden object_pairs_hookwerden können. Mirec Miskufs Antwort ist bislang die einzige, die es schafft, dies richtig durchzuziehen, obwohl sie infolgedessen wesentlich komplizierter ist als mein Ansatz.
Mark Amery
quelle
1
Ich mag das - es ist kein Ignorieren - es erkennt, dass Leute, die "Strings" und "ASCII" sagen, meistens naiv meinten, sie wollten Bytes, keine theoretischen Unicode-Zeichen. (und nicht ascii, da sie noch Pfundzeichen am anderen Ende wollen)
Danny Staple
Ich mag das, es funktioniert fast genauso wie mein hübscher Drucker, da ich weiß, dass json kein Tupel macht, sollten Sie auch die Ausnahme für Tupel hinzufügen.
y.petremann
Dies ist schrecklich ineffizient und erfordert, dass Sie Knoten rekursiv durchlaufen, die Sie möglicherweise nicht benötigen. Das json-Modul bietet Ihnen Hooks, um dies viel effizienter zu tun. Die folgende Antwort object_hookist zwar weitaus schlechter als diese, aber mit object_pairs_hookkönnen Sie eine einigermaßen effiziente Methode finden , die keine Rekursion oder erneute Überprüfung von Knoten erfordert, die keine Zeichenfolgen enthalten.
Travis Jensen
1
@TravisJensen Interessant. Die object_pairs_hookMethode ist vielleicht etwas schwieriger zu verstehen als diese (Sie müssen verstehen, wie der Parameter funktioniert und warum Listen und Diktate eine andere Behandlung erfordern), und der Leistungsvorteil wird für die meisten Menschen keine Rolle spielen ... aber ich würde erwarten Es muss existieren, insbesondere für alle, die sich mit einem ungewöhnlich tief verschachtelten JSON-Objekt befassen.
Mark Amery
plus1 Dies ist die prägnanteste Antwort. Außerdem ist PyYAML ein Problem bei der Installation. Das einzig Bessere wäre, die Konvertierung irgendwie per Mikro-Stream zu übertragen, damit kein 4X-Speicher verwendet wird.
personal_cloud
74

Mit dem object_hookParameter für können Sie json.loadseinen Konverter übergeben. Sie müssen die Konvertierung nicht nachträglich durchführen. Das jsonModul übergibt immer object_hooknur die Diktate und rekursiv verschachtelte Diktate, sodass Sie nicht selbst in verschachtelte Diktate zurückgreifen müssen. Ich glaube nicht, dass ich Unicode-Strings in Zahlen wie Wells-Shows konvertieren würde. Wenn es sich um eine Unicode-Zeichenfolge handelt, wurde sie in der JSON-Datei als Zeichenfolge angegeben, daher sollte es sich um eine Zeichenfolge handeln (oder die Datei ist fehlerhaft).

Außerdem würde ich versuchen, so etwas wie str(val)ein unicodeObjekt zu vermeiden . Sie sollten value.encode(encoding)eine gültige Codierung verwenden, je nachdem, was Ihre externe Bibliothek erwartet.

Also zum Beispiel:

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)
Mike Brennan
quelle
3
Dies ist in Ordnung, wenn das Objekt in sein JSON ist Object(eine ungeordnete Sammlung von Schlüssel: Wert-Paaren mit dem Zeichen ':', das den Schlüssel und den Wert trennt, durch Kommas getrennt und in geschweiften Klammern eingeschlossen), aber nicht, wenn es sich beispielsweise um a handelt JSON Array. Wenn Sie also einen JSON- Arrayähnlichen Wert erhalten ["a", "b"], bleibt das Ergebnis erhalten [u'a', u'b']. Keiner der anderen derzeit verfügbaren Customizing-Hook-Parameter für json.loads()kann diese Aufgabe ausführen.
Martineau
2
Da das jsonModul , wie Sie bereits erwähnt haben, verschachtelte dicts rekursiv übergibt , ist es nicht erforderlich, in den beiden Funktionen elifnach ihnen zu suchen. Daher sollten die beiden Klauseln, die nach ihnen suchen, entfernt werden.
Martineau
1
Beachten Sie, dass das Starten von Funktionsnamen mit einem Unterstrich eine besondere Bedeutung für Importanweisungen hat. Wenn Sie diese Funktionen in eine Datei mit dem Namen Utility.py und in eine andere Datei einfügen from Utility import *, werden die Funktionen aufgrund dieses Unterstrichs nicht angezeigt .
M Katz
1
Das ist eine wirklich schlechte Idee. object_hookwird für jedes analysierte JSON-Objekt aufgerufen. Wenn Sie also auf das zurückgreifen, was Ihnen gegeben wurde, "byteifizieren" Sie Dinge, die Sie bereits "byteifiziert" haben. Die Leistung wird geometrisch mit der Größe des Objekts zunehmen. Ich habe hier eine Antwort eingefügt , die object_pairs_hookdieses Problem verwendet und nicht darunter leidet.
Travis Jensen
38

Das liegt daran, dass json keinen Unterschied zwischen String-Objekten und Unicode-Objekten hat. Sie sind alle Zeichenfolgen in Javascript.

Ich denke, JSON ist richtig, um Unicode-Objekte zurückzugeben . Tatsächlich würde ich nichts weniger akzeptieren, da Javascript-Zeichenfolgen tatsächlich unicodeObjekte sind (dh JSON-Zeichenfolgen (Javascript) können jede Art von Unicode-Zeichen speichern). Daher ist es sinnvoll, unicodeObjekte zu erstellen , wenn Zeichenfolgen aus JSON übersetzt werden. Einfache Zeichenfolgen würden einfach nicht passen, da die Bibliothek die gewünschte Codierung erraten müsste.

Es ist besser, unicodeüberall String-Objekte zu verwenden . Am besten aktualisieren Sie Ihre Bibliotheken, damit sie mit Unicode-Objekten umgehen können.

Wenn Sie jedoch wirklich Bytestrings möchten, codieren Sie die Ergebnisse einfach in die Codierung Ihrer Wahl:

>>> nl = json.loads(js)
>>> nl
[u'a', u'b']
>>> nl = [s.encode('utf-8') for s in nl]
>>> nl
['a', 'b']
nosklo
quelle
Danke nosklo, das habe ich zuerst gemacht. Aber wie gesagt, die realen Daten, die ich verwendet habe, sind ziemlich verschachtelt und alles, was zu einem gewissen Overhead führte. Ich bin immer noch auf der Suche nach einer automatischen Lösung ... Es gibt mindestens einen Fehlerbericht, in dem sich Leute darüber beschweren, dass simplejson String-Objekte anstelle von Unicode zurückgibt.
Brutus
1
@Brutus: Ich denke, json ist richtig, Unicode-Objekte zurückzugeben. Tatsächlich würde ich nichts weniger akzeptieren, da Javascript-Zeichenfolgen tatsächlich Unicode-Objekte sind. Was ich damit meine ist, dass Json-Zeichenfolgen (Javascript) jede Art von Unicode-Zeichen speichern können. Daher ist es sinnvoll, bei der Übersetzung von Json Unicode-Objekte zu erstellen. Sie sollten stattdessen wirklich Ihre Bibliotheken reparieren.
Nosklo
16

Es gibt eine einfache Umgehung.

TL; DR - Verwenden Sie ast.literal_eval()anstelle von json.loads(). Beide astund jsonsind in der Standardbibliothek.

Obwohl dies keine „perfekte“ Antwort ist, ist es ziemlich weit, wenn Sie Unicode ganz ignorieren möchten. In 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))

gibt:

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

Dies wird haariger, wenn einige Objekte wirklich Unicode-Zeichenfolgen sind. Die vollständige Antwort wird schnell haarig.

Charles Merriam
quelle
11
Besser sicher sein , Ihre json enthält keine null, trueoder falseWerte, weil sie nicht gültig in Python sind und dazu führen , literal_eval()zum Scheitern verurteilt.
10sәɹoɈ
3
@ ʇsәɹoɈ Hoffen Sie auch besser, dass Ihr JSON keinen Escape-Solidus ( \/) in einer Zeichenfolge oder eine Unicode-Escape-Sequenz (wie "\u0061"eine andere Schreibweise "a") enthält. Die wörtliche Syntax von Python ist in mehrfacher Hinsicht nicht mit JSON kompatibel, und ich würde dieser Antwort für kein Skript vertrauen, das ich nicht wegwerfen würde.
Mark Amery
Die Leute haben Recht, wenn diese Zeichenfolge wirklich Unicode ist, schlägt diese Antwort fehl, aber wenn dies der Fall wäre, könnten wir sie sowieso nicht in eine Zeichenfolge umwandeln. +1 für eine Antwort, die nur funktioniert, wenn sie funktioniert und ansonsten eine Ausnahme auslöst
Stefan Sullivan
Wenn möglich, nicht jsonzum Speichern der Daten verwenden, sondern nur, printwenn Python ausgeführt wird. Dann ast.literal_evalfunktioniert
Jean-François Fabre
11

Die Antwort von Mike Brennan ist knapp, aber es gibt keinen Grund, die gesamte Struktur erneut zu durchqueren. Wenn Sie den object_hook_pairsParameter (Python 2.7+) verwenden:

object_pairs_hookist eine optionale Funktion, die mit dem Ergebnis eines Objektliteral aufgerufen wird, das mit einer geordneten Liste von Paaren dekodiert wurde. Der Rückgabewert von object_pairs_hookwird anstelle von verwendet dict. Diese Funktion kann verwendet werden, um benutzerdefinierte Decoder zu implementieren, die von der Reihenfolge abhängen, in der die Schlüssel- und Wertepaare decodiert werden (wobei beispielsweise collections.OrderedDictdie Reihenfolge des Einfügens gespeichert wird). Wenn object_hookauch definiert, hat das object_pairs_hookPriorität.

Damit erhalten Sie jedes JSON-Objekt, sodass Sie die Dekodierung ohne Rekursion durchführen können:

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'}}

Beachten Sie, dass ich den Hook nie rekursiv aufrufen muss, da jedes Objekt an den Hook übergeben wird, wenn Sie den verwenden object_pairs_hook. Sie müssen sich um Listen kümmern, aber wie Sie sehen können, wird ein Objekt in einer Liste ordnungsgemäß konvertiert, und Sie müssen nicht rekursiv arbeiten, um dies zu erreichen.

EDIT: Ein Mitarbeiter wies darauf hin, dass Python2.6 nicht hat object_hook_pairs. Sie können diesen Python2.6 weiterhin verwenden, indem Sie eine sehr kleine Änderung vornehmen. Ändern Sie im Haken oben:

for key, value in pairs:

zu

for key, value in pairs.iteritems():

Dann verwenden Sie object_hookanstelle von 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'}}

Wenn Sie object_pairs_hookErgebnisse verwenden, wird für jedes Objekt im JSON-Objekt ein Wörterbuch weniger instanziiert. Wenn Sie ein großes Dokument analysieren, lohnt sich dies möglicherweise.

Travis Jensen
quelle
1
Dies ist ordentlich und scheint dem grünen Häkchen sehr nahe zu sein (das Brutus bewundernswerterweise bereits großzügig herumgereicht hat, da bessere Antworten eingegangen sind). Aber ... warum nicht tatsächlich richtig mit Listen umgehen deunicodify_hook, die Sie in dieser Antwort ausstellen? Im Moment haben Sie eine Implementierung deunicodify_hook, die nicht über Listen iteriert und die darin enthaltenen Zeichenfolgen und Listen entkodifiziert. Daher stimmt die Ausgabe, die Sie anzeigen, nicht mit der Ausgabe überein, die Ihr Hook tatsächlich erzeugt. Beheben Sie das, und diese Antwort ist meiner überlegen.
Mark Amery
Frivol: Ich würde auch vorschlagen, die Funktion mit dem normalen CPython-Interpreter zu demonstrieren, anstatt mit dem, den Sie hier verwenden (was ich für IronPython halte). Der CPython-Interpreter ist den meisten Python-Benutzern besser bekannt und meiner Meinung nach hübscher.
Mark Amery
Das funktioniert bei mir nicht, aber ich bin sicher, es ist eine Eigenart von dem, was ich tue ... Ich speichere eine Liste aus einem größeren JSON-Dokument in einer Datei. Unabhängig davon, ob ich es mit oder ohne diesen object_pairs_hook lade, wird jedes Element als Unicode angezeigt. Verflixt.
rsaw
1
@rsaw Guter Punkt! Da object_pairs_hooknur für Objekte aufgerufen wird , schlägt diese Lösung fehl, wenn Ihr JSON-Text eine Liste von Zeichenfolgen auf der obersten Ebene enthält. Es gibt keine Möglichkeit, dies zu beheben, ohne eine Funktion für das zurückgegebene Objekt aufzurufen json.load. Keiner der json.loadHaken kann garantieren, dass Sie mit jeder Saite umgehen können. Ich denke, dies ist ein Fehler, der groß genug ist, um meine Lösung weiterhin über die Verwendung der Haken zu empfehlen.
Mark Amery
-1, weil ich gerade festgestellt habe, dass Mirec Miskuf bereits eine Objekt-Hook-Antwort veröffentlicht hat, die weder die Nachteile von Mike Brennans Ansatz (die gleichen Wörterbücher mehrmals neu byteifizieren) noch von diesem Ansatz (verschachtelte Listen oder Listen der obersten Ebene nicht zu byteifizieren) aufweist oder Strings). Ich bin mir nicht sicher, warum seine Antwort fast ohne Aufmerksamkeit nachgelassen hat, während diese - die minderwertig ist - schnell Stimmen erhalten hat.
Mark Amery
9

Ich fürchte, es gibt keine Möglichkeit, dies automatisch in der simplejson-Bibliothek zu erreichen.

Der Scanner und Decoder in simplejson sind für die Erzeugung von Unicode-Text ausgelegt. Zu diesem Zweck verwendet die Bibliothek eine Funktion namens c_scanstring(falls verfügbar, aus Gründen der Geschwindigkeit) oder py_scanstringwenn die C-Version nicht verfügbar ist. Die scanstringFunktion wird von fast jeder Routine, die simplejson zum Dekodieren einer Struktur hat, die möglicherweise Text enthält, mehrmals aufgerufen. Sie scanstringmüssten entweder den Wert in simplejson.decoder oder eine Unterklasse monkeypatchen JSONDecoderund so ziemlich Ihre gesamte Implementierung von allem bereitstellen, was Text enthalten könnte.

Der Grund, warum simplejson Unicode ausgibt, ist, dass in der json-Spezifikation ausdrücklich erwähnt wird, dass "Eine Zeichenfolge eine Sammlung von null oder mehr Unicode-Zeichen ist" ... Unterstützung für Unicode wird als Teil des Formats selbst angenommen. Die scanstringImplementierung von Simplejson geht so weit, Unicode- Escapezeichen zu scannen und zu interpretieren (sogar die Fehlerprüfung auf fehlerhafte Mehrbyte-Zeichensatzdarstellungen). Der einzige Weg, den Wert zuverlässig an Sie zurückzugeben, ist Unicode.

Wenn Sie eine veraltete Bibliothek haben, die eine benötigt str, empfehle ich Ihnen, entweder die verschachtelte Datenstruktur nach dem Parsen mühsam zu durchsuchen (was ich ausdrücklich als das bezeichne, was Sie ausdrücklich vermeiden wollten ... Entschuldigung) oder Ihre Bibliotheken in eine Art zu verpacken Fassade, wo Sie die Eingabeparameter auf einer detaillierteren Ebene massieren können. Der zweite Ansatz ist möglicherweise einfacher zu handhaben als der erste, wenn Ihre Datenstrukturen tatsächlich tief verschachtelt sind.

Jarret Hardie
quelle
4

Wie Mark (Amery) richtig bemerkt: Die Verwendung von PyYamls Deserializer auf einem JSON-Dump funktioniert nur, wenn Sie nur über ASCII verfügen. Zumindest sofort.

Zwei kurze Kommentare zum PyYaml-Ansatz:

  1. NIEMALS yaml.load auf Daten aus dem Feld. Es ist eine Funktion (!) Von yaml, um beliebigen Code auszuführen, der in der Struktur versteckt ist.

  2. Sie können es auch für Nicht-ASCII-Dateien so einrichten:

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

Aber die Leistung ist nicht mit Mark Amerys Antwort zu vergleichen:

Wenn ich einige tief verschachtelte Beispieldiktate auf die beiden Methoden wirf, erhalte ich Folgendes (mit dt [j] = Zeitdelta von json.loads (json.dumps (m))):

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

Deserialisierung, einschließlich vollständiges Durchlaufen des Baums und Codierung, in der Größenordnung der C-basierten Implementierung von json. Ich finde das bemerkenswert schnell und es ist auch robuster als die Yaml-Ladung bei tief verschachtelten Strukturen. Und weniger anfällig für Sicherheitsfehler, wenn man sich yaml.load ansieht.

=> Während ich einen Zeiger auf einen C-basierten Konverter begrüßen würde, sollte die Byteify-Funktion die Standardantwort sein.

Dies gilt insbesondere dann, wenn Ihre JSON-Struktur aus dem Feld stammt und Benutzereingaben enthält. Denn dann müssen Sie wahrscheinlich trotzdem über Ihre Struktur gehen - unabhängig von Ihren gewünschten internen Datenstrukturen (nur 'Unicode-Sandwich' oder Byte-Strings).

Warum?

Unicode- Normalisierung . Für Unbewusste: Nehmen Sie ein Schmerzmittel und lesen Sie dies .

Mit der Byteify-Rekursion töten Sie also zwei Fliegen mit einer Klappe:

  1. Holen Sie sich Ihre Bytestrings von verschachtelten JSON-Dumps
  2. Normalisieren Sie die Benutzereingabewerte, damit Sie das Material in Ihrem Speicher finden.

In meinen Tests stellte sich heraus, dass das Ersetzen des input.encode ('utf-8') durch einen unicodedata.normalize ('NFC', Eingabe) .encode ('utf-8') noch schneller war als ohne NFC - aber Das hängt stark von den Beispieldaten ab, denke ich.

Rote Pille
quelle
3

Die gotcha ist , dass simplejsonund jsonsind zwei verschiedene Module, zumindest in der Form , die sie mit Unicode umgehen. Sie haben jsonin py 2.6+ und dies gibt Ihnen Unicode-Werte, während simplejsonString-Objekte zurückgegeben werden. Versuchen Sie einfach easy_installing simplejson in Ihrer Umgebung und prüfen Sie, ob dies funktioniert. Es hat für mich getan.

ducu
quelle
2

Verwenden Sie einfach Pickle anstelle von JSON für Dump und Load, wie folgt:

    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"))

Die Ausgabe ist (Zeichenfolgen und Ganzzahlen werden korrekt behandelt):

    {u'field2': 2, u'field1': u'value1'}
    {'field2': 2, 'field1': 'value1'}
Stefan Gruenwald
quelle
1
+1 für eine Lösung, die keine zusätzlichen Pakete erfordert (wie yaml ). Aber manchmal - wie in meinem ursprünglichen Fall - muss ich die Daten in JSON haben, daher ist Pickle nicht immer die beste Option. Außerdem haben Sie safe_loadin YAML, ich weiß nicht, ob es etwas Ähnliches für Gurke gibt .
Brutus
1

Also bin ich auf das gleiche Problem gestoßen. Ratet mal, was das erste Google-Ergebnis war.

Da ich alle Daten an PyGTK übergeben muss, sind Unicode-Zeichenfolgen für mich auch nicht sehr nützlich. Ich habe also eine andere rekursive Konvertierungsmethode. Es wird tatsächlich auch für die typsichere JSON-Konvertierung benötigt - json.dump () würde auf Nicht-Literale wie Python-Objekte zugreifen. Konvertiert jedoch keine Diktatindizes.

# 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
Mario
quelle
Das einzige Problem, das hier auftreten kann, ist, wenn Sie die Schlüssel in einem von Unicode konvertierten Wörterbuch benötigen. Diese Implementierung konvertiert zwar die Werte, behält jedoch die Unicode-Schlüssel bei. Wenn Sie ein 'newobj' erstellen, newobj [str (i)] = ... verwenden und obj = newobj zuweisen, wenn Sie fertig sind, werden auch die Schlüssel konvertiert.
Neal Stublen
Dies könnte mit Verständnis schöner sein oder besser durch Konvertieren von Schlüsseln. Es ist auch unidiomatisch; Beide mutieren vorhandene Objekte (im Fall von Wörterbüchern) und geben den neuen Wert zurück, was nicht mit den in Python integrierten Erfassungsmethoden vereinbar ist, die entweder das aktuelle Objekt mutieren oder ein neues zurückgeben, aber nicht beide.
Mark Amery
1

Ich hatte ein JSON-Diktat als Zeichenfolge. Die Schlüssel und Werte waren Unicode-Objekte wie im folgenden Beispiel:

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

Ich könnte die byteifyoben vorgeschlagene Funktion verwenden, indem ich die Zeichenfolge mit in ein dictObjekt konvertiere ast.literal_eval(myStringDict).

Narko
quelle
Das von Ihnen angegebene Beispiel ist kein Beispiel für JSON. {u'key':u'value'}ist nicht JSON.
Mark Amery
2
Ich weiß genau, dass es nicht JSON ist. So wurde es von einer externen Quelle in meinem Python-Skript analysiert. Wenn es JSON direkt wie im folgenden Beispiel wäre, würde ich die als Lösung gekennzeichnete Byteify-Funktion nicht benötigen: {"Vorname": "John", "Nachname": "Doe"}. Es wäre einfach toll, wenn Sie vor der Abstimmung die Antworten lesen würden. Vielen Dank.
Narko
1

Unterstützt Python2 & 3 mit Hook (von https://stackoverflow.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)

Kehrt zurück:

 {'three': '', 'key': 'value', 'one': 'two'}
abarik
quelle
0

Das ist spät im Spiel, aber ich habe diesen rekursiven Zaubernden gebaut. Es funktioniert für meine Bedürfnisse und ich denke, es ist relativ vollständig. Es kann Ihnen helfen.

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

Übergeben Sie einfach ein JSON-Objekt wie folgt:

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

Ich habe es als privates Mitglied einer Klasse, aber Sie können die Methode nach Belieben neu verwenden.

Wells
quelle
Ich bin auf ein Problem gestoßen, bei dem ich versuche, JSON zu analysieren und die resultierende Zuordnung an eine Funktion als ** kwargs zu übergeben. Es sieht so aus, als ob Funktionsparameternamen kein Unicode sein können, daher ist Ihre _parseJSON-Funktion großartig. Wenn es einen einfacheren Weg gibt, kann mich jemand informieren.
Neal Stublen
1
Dieser Code hat ein Problem: Sie führen einen rekursiven Aufruf im Listenelement durch, der fehlschlägt, wenn die Elemente der Liste selbst keine Wörterbücher sind.
I82Much
Neben dem von @ I82Much beschriebenen Fehler ist dieser auch schlecht benannt (er analysiert den JSON nicht wirklich; ein json.loadsAufruf ist zuerst erforderlich), versucht willkürlich, Zeichenfolgen ohne erklärten Grund in Ints umzuwandeln, und ist kein Kopieren und- Paste fertig.
Mark Amery
0

Ich habe Wells '_parse_json () neu geschrieben, um Fälle zu behandeln, in denen das json-Objekt selbst ein Array ist (mein Anwendungsfall).

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
Darnmarshall
quelle
0

Hier ist ein rekursiver Encoder in C: https://github.com/axiros/nested_encode

Leistungsaufwand für "durchschnittliche" Strukturen um 10% im Vergleich zu 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%

mit dieser Teststruktur:

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)
Rote Pille
quelle
0

Mit Python 3.6 stoße ich manchmal immer noch auf dieses Problem. Wenn ich beispielsweise eine Antwort von einer REST-API erhalte und den Antworttext in JSON lade, erhalte ich immer noch die Unicode-Zeichenfolgen. Mit json.dumps () eine einfache Lösung gefunden.

response_message = json.loads(json.dumps(response.text))
print(response_message)
Yuelin
quelle
-1

Ich bin auch auf dieses Problem gestoßen, und da ich mich mit JSON befassen musste, kam ich auf eine kleine Schleife, die die Unicode-Schlüssel in Zeichenfolgen konvertiert. (Bei simplejsonGAE werden keine Zeichenfolgenschlüssel zurückgegeben.)

obj ist das aus JSON dekodierte Objekt:

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()

kwargsist das, was ich an den Konstruktor der GAE-Anwendung übergebe (die keine unicodeSchlüssel mag **kwargs)

Nicht so robust wie die Lösung von Wells, aber viel kleiner.

Bootscodierer
quelle
-1

Ich habe den Code aus der Antwort von Mark Amery angepasst , insbesondere um ihn isinstancefür die Profis des Ententypens loszuwerden .

Die Codierung erfolgt manuell und ensure_asciiist deaktiviert. Die Python-Dokumente für json.dumpsagen das

Wenn sure_ascii True ist (Standardeinstellung), werden alle Nicht-ASCII-Zeichen in der Ausgabe mit \ uXXXX-Sequenzen maskiert

Haftungsausschluss: Im Doctest habe ich die ungarische Sprache verwendet. Einige bemerkenswerte ungarische Zeichenkodierungen sind: cp852die verwendete IBM / OEM-Kodierung, z. in DOS (manchmal als ASCII bezeichnet , fälschlicherweise denke ich, es hängt von der Codepage- Einstellung ab), cp1250z. in Windows (manchmal als ansi bezeichnet , abhängig von den Ländereinstellungen ) und iso-8859-2manchmal auf http-Servern verwendet. Der Testtext Tüskéshátú kígyóbűvölőwird Koltai László (einheimische Form des persönlichen Namens) zugeschrieben und stammt aus 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://stackoverflow.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)

Ich möchte auch die Antwort von Jarret Hardie hervorheben, die auf die JSON-Spezifikation verweist und Folgendes zitiert:

Eine Zeichenfolge ist eine Sammlung von null oder mehr Unicode-Zeichen

In meinem Anwendungsfall hatte ich Dateien mit json. Sie sind utf-8verschlüsselte Dateien. ensure_asciiführt zu ordnungsgemäß maskierten, aber nicht gut lesbaren JSON-Dateien. Deshalb habe ich Mark Amerys Antwort an meine Bedürfnisse angepasst.

Das Doctest ist nicht besonders nachdenklich, aber ich teile den Code in der Hoffnung, dass er für jemanden nützlich sein wird.

n611x007
quelle
Ich bin mir nicht sicher, ob ich die Vorteile der Ententypisierung hier sehe. Wir wissen, dass es sich bei den zurückgegebenen Sammlungen json.loadsum Listen oder Diktate handelt, nicht um benutzerdefinierte oder bibliotheksdefinierte Typen, die ihre Methoden und magischen Methoden implementieren. Warum also nicht einfach eine isinstanceÜberprüfung durchführen? Ist das nicht einfacher zu verstehen, als zu prüfen, iteritemsob iterdas Objekt vorhanden ist oder ob es als Argument akzeptiert wird?
Mark Amery
@ MarkAmery Hier geht es um Dumps, nicht um Ladungen. Wenn Sie Daten zum Speichern erstellen , anstatt sie zu laden, können Sie nicht sicher sein, um was es sich handelt. Die Idee war, es von irgendwo im Code kommen zu lassen.
n611x007
-2

Schauen Sie sich diese Antwort auf eine ähnliche Frage an, die dies besagt

Das U-Präfix bedeutet nur, dass Sie eine Unicode-Zeichenfolge haben. Wenn Sie die Zeichenfolge wirklich verwenden, wird sie in Ihren Daten nicht angezeigt. Lassen Sie sich nicht von der gedruckten Ausgabe werfen.

Versuchen Sie zum Beispiel Folgendes:

print mail_accounts[0]["i"]

Du wirst kein u sehen.

kunal
quelle
Nicht wahr, wenn Sie beispielsweise etwas in Py2 formatieren möchten, das eine Unicode-Zeichenfolge enthält. zB '{}'.format({u'x' : u'y'})schließt noch die u's ein.
Ponkadoodle