wake-up-neo.com

Wie erhält man String-Objekte anstelle von Unicode von JSON?

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

Wenn Sie diese Dateien mit json oder simplejson laden, werden alle meine String-Werte in Unicode-Objekte umgewandelt und nicht in String-Objekten. Das Problem ist, ich muss die Daten mit einigen Bibliotheken verwenden, die nur Zeichenkettenobjekte akzeptieren. Ich kann die Bibliotheken nicht ändern oder sie nicht aktualisieren.

Kann man anstelle von Unicode-Objekten String-Objekte erhalten?

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 festhielt. Eine einfache und saubere Lösung für heute ist die Verwendung einer aktuellen Version von Python - d. H. Python 3 und weiter.

255
Brutus

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

Verwendungsbeispiel:

>>>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, also was ist der Sinn von ihnen? Warum möchtest du sie verwenden?

Nur für performance. Marks Antwort dekodiert den JSON-Text zunächst 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 Pythons maximale Rekursionstiefe

Diese Antwort verringert beide dieser Leistungsprobleme, indem der object_hook-Parameter von json.load und json.loads verwendet wird. Von den Dokumenten :

object_hook ist eine optionale Funktion, die mit dem Ergebnis eines dekodierten Objektliteral (dict) aufgerufen wird. Der Rückgabewert von object_hook wird anstelle von dict verwendet. Diese Funktion kann verwendet werden, um benutzerdefinierte Decoder zu implementieren

Da Wörterbücher, die viele Ebenen tief in anderen Wörterbüchern verschachtelt sind, an object_hookübergeben werden, während sie dekodiert werden, können wir alle Zeichenfolgen oder Listen, die sich in ihnen befinden, zu diesem Zeitpunkt byteifizieren und später eine tiefe Rekursion vermeiden.

Marks Antwort ist nicht als object_hook geeignet, da sie in verschachtelte Wörterbücher rekursiert. Wir verhindern diese Rekursion in dieser Antwort mit dem ignore_dicts-Parameter zu _byteify, der jederzeit an übergeben wird, außer, wenn object_hook ihm einen neuen dict zum Byte gibt. Das ignore_dicts-Flag weist _byteify an, dicts zu ignorieren, da sie bereits byteifiziert wurden.

Schließlich haben unsere Implementierungen von json_load_byteified und json_loads_byteified den Aufruf _byteify (mit ignore_dicts=True) des Ergebnisses, das von json.load oder json.loads zurückgegeben wird, um den Fall zu behandeln, in dem der zu dekodierende JSON-Text auf der obersten Ebene nicht dict ist.

89
Mirec Miskuf

Obwohl es hier einige gute Antworten gibt, habe ich letztendlich PyYAML zum Parsen meiner JSON-Dateien verwendet, da die Schlüssel und Werte als str-Zeichenfolge anstelle von unicode-Typ 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 bekomme string objects, 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ückgeben - es gibt keine Konvertierung!

  • Sie sollten (wahrscheinlich immer) die safe_load-Funktion von PyYAML verwenden. Wenn Sie es verwenden, um JSON-Dateien zu laden, benötigen Sie sowieso nicht die "zusätzliche Leistung" der Funktion load.

  • Wenn Sie einen YAML-Parser suchen, der mehr Unterstützung für die 1.2-Version der Spezifikation bietet (und analysiert sehr niedrige Zahlen ), versuchen Sie Ruamel YAML : pip install ruamel.yaml und import ruamel.yaml as yaml waren alles, was ich in meinem Computer brauchte Tests.

Umwandlung

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

Ich habe jetzt ein paar Mal von Mark Amery verwendet, es funktioniert hervorragend und ist sehr einfach zu bedienen. Sie können stattdessen auch eine ähnliche Funktion als object_hook verwenden, da dies bei großen Dateien zu einer Leistungssteigerung führen kann. Sehen Sie dazu das etwas ausführlichere Antwort von Mirec Miskuf .

169
Brutus

Es gibt keine integrierte Option, mit der die json-Modulfunktionen 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-kodierte 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 in der Ausgabe auf, die Sie von einem json.load- oder json.loads-Aufruf erhalten.

Ein paar Anmerkungen:

  • Um Python 2.6 oder eine frühere Version 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 Wörterbücher nicht bis Python 2.7 unterstützt werden.
  • Da diese Antwort durch das gesamte dekodierte Objekt wiederholt wird, weist sie eine Reihe unerwünschter Leistungsmerkmale auf, die durch sorgfältige Verwendung der Parameter object_hook oder object_pairs_hook vermieden werden können. Mirec Miskufs Antwort ist bis jetzt der einzige, der das richtig hinbekommt, obwohl er dadurch wesentlich komplizierter ist als mein Ansatz.
139
Mark Amery

Sie können den object_hook-Parameter für json.loads verwenden, um einen Konverter zu übergeben. Sie müssen die Konvertierung nicht danach durchführen. Das json -Modul wird immer nur die object_hook -Dictes durchlaufen, und es wird rekursiv in verschachtelten Diktaten durchlaufen, so dass Sie nicht selbst in verschachtelten Diktaten rekursieren 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 als Zeichenfolge in der JSON-Datei angegeben. Es handelt sich also vermutlich um eine Zeichenfolge (oder die Datei ist fehlerhaft).

Ich würde auch versuchen, etwas wie str(val) für ein unicode-Objekt zu vermeiden. Sie sollten value.encode(encoding) mit einer gültigen Kodierung 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)
73
Mike Brennan

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

Ich denke, JSON ist berechtigt, Unicode-Objekte zurückzugeben. In der Tat würde ich nichts weniger akzeptieren, da die JavaScript-Zeichenfolgen sind tatsächlich unicode Objekte (dh JSON-Zeichenfolgen (Javascript) können jede Art mit Unicode-Zeichen speichern), so dass es sinnvoll ist, diese zu erstellen unicode Objekte beim Übersetzen von Strings aus JSON. Einfache Strings würden einfach nicht passen, da die Bibliothek die gewünschte Kodierung erraten müsste.

Es ist besser, unicode-Stringobjekte überall zu verwenden. Daher ist es am besten, wenn Sie Ihre Bibliotheken aktualisieren, damit sie mit Unicode-Objekten umgehen können.

Wenn Sie wirklich Bytestrings wünschen, 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']
37
nosklo

Es gibt eine einfache Umgehung.

TL; DR - Verwenden Sie ast.literal_eval() anstelle von json.loads(). Sowohl ast als auch json befinden sich in der Standardbibliothek.

Auch wenn dies keine "perfekte" Antwort ist, wird es ziemlich weit, wenn Sie Unicode komplett 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 volle Antwort wird schnell haarig.

15
Charles Merriam

Mike Brennans Antwort ist nahe, aber es gibt keinen Grund, die gesamte Struktur erneut zu durchlaufen. Wenn Sie den Parameter object_hook_pairs (Python 2.7+) verwenden, gilt Folgendes:

object_pairs_hook ist eine optionale Funktion, die mit dem Ergebnis eines Objektliteral aufgerufen wird, das mit einer geordneten Liste von Paaren dekodiert wird. Der Rückgabewert von object_pairs_hook wird anstelle der dict verwendet. Diese Funktion kann verwendet werden, um benutzerdefinierte Decoder zu implementieren, die auf der Reihenfolge basieren, in der die Schlüssel- und Wertepaare decodiert werden (z. B. collections.OrderedDict speichert die Reihenfolge des Einfügens). Wenn auch object_hook definiert ist, hat der object_pairs_hook Priorität.

Damit erhalten Sie jedes JSON-Objekt, das Sie erhalten, 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 bei Verwendung des object_pairs_hook jedes Objekt an den Hook übergeben wird. Sie müssen sich zwar um Listen kümmern, aber wie Sie sehen, wird ein Objekt in einer Liste ordnungsgemäß konvertiert, und Sie müssen nicht erneut rekursieren, um dies zu ermöglichen.

BEARBEITEN: Ein Mitarbeiter hat darauf hingewiesen, dass Python2.6 keinen object_hook_pairs hat. Sie können dieses 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():

Verwenden Sie dann object_hook anstelle 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'}}

Die Verwendung von object_pairs_hook führt dazu, dass für jedes Objekt im JSON-Objekt ein Wörterbuch weniger instanziiert wird, das sich bei der Analyse eines umfangreichen Dokuments möglicherweise lohnt.

10
Travis Jensen

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

Scanner und Decoder in simplejson sind so konzipiert, dass sie Unicode-Text erzeugen. Zu diesem Zweck verwendet die Bibliothek eine Funktion namens c_scanstring (falls verfügbar, Geschwindigkeit) oder py_scanstring, wenn die C-Version nicht verfügbar ist. Die scanstring-Funktion wird von fast jeder Routine, die simplejson zum Dekodieren einer Struktur mit Text enthält, mehrmals aufgerufen. Sie müssen entweder den Wert scanstring in simplejson.decoder monkeypatchen oder die Unterklasse JSONDecoder angeben und so ziemlich Ihre gesamte Implementierung von allem bereitstellen, der Text enthält.

Der Grund für die Ausgabe von Unicode durch simplejson ist jedoch, dass in der json spec ausdrücklich erwähnt wird, dass "eine Zeichenfolge eine Sammlung von null oder mehr Unicode-Zeichen ist" ... die Unterstützung für Unicode als Teil des Formats selbst angenommen wird. Simplejsons scanstring-Implementierung geht so weit, Unicode-Escape-Codes zu scannen und zu interpretieren (sogar die Fehlerprüfung für missgebildete Mehrbyte-Zeichensätze). Die einzige Möglichkeit, den Wert zuverlässig an Sie zu übergeben, ist Unicode.

Wenn Sie über eine veraltete Bibliothek verfügen, die eine str benötigt, empfehle ich Ihnen, entweder nach dem Parsen die verschachtelte Datenstruktur mühsam zu durchsuchen (was Sie ausdrücklich sagen, Sie wollten es vermeiden ... Entschuldigung) oder Ihre Bibliotheken in gewisser Weise einpacken der Fassade, wo Sie die Eingabeparameter auf einer feineren Ebene massieren können. Der zweite Ansatz ist möglicherweise überschaubarer als der erste, wenn Ihre Datenstrukturen tatsächlich tief verschachtelt sind.

9
Jarret Hardie

Wie Mark (Amery) richtig bemerkt: Die Verwendung von PyYaml 's Deserializer auf einem Json-Dump funktioniert nur, wenn Sie ASCII Zumindest aus der Schachtel.

Zwei kurze Kommentare zum PyYaml-Ansatz:

  1. NEVER benutze yaml.load für Daten aus dem Feld. Es ist eine Funktion (!) Von yaml, um beliebigen Code auszuführen, der in der Struktur verborgen ist.

  2. Sie können machen es auch für Nicht ASCII über diese:

    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 was die Leistung angeht, ist das mit Mark Amerys Antwort nicht zu vergleichen:

Wenn ich einige tief verschachtelte Beispieldiktate auf die beiden Methoden ziehe, 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 des vollständigen Durchlaufens des Baums und Codierung, liegt also in der Größenordnung der C-basierten Implementierung von json. Ich finde das bemerkenswert schnell und es ist auch robuster als die yaml Last 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 ohnehin über Ihre Struktur gehen - unabhängig von Ihren gewünschten internen Datenstrukturen ('Unicode-Sandwich' oder nur Byte-Strings).

Warum?

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

Mit der Rekursion byteify schlagen Sie also zwei Fliegen mit einer Klappe:

  1. holen Sie sich Ihre Bytestrings von verschachtelten JSON-Dumps
  2. die Benutzereingabewerte werden normalisiert, 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', input) .encode ('utf-8') sogar schneller war als ohne NFC - aber das hängt stark von den Beispieldaten ab, denke ich.

4
Red Pill

Die Gotcha ist, dass simplejson und json zwei verschiedene Module sind, zumindest in der Art und Weise, wie sie mit Unicode umgehen. Sie haben json in py 2.6+ und dies gibt Ihnen Unicode-Werte, wohingegen simplejson Zeichenkettenobjekte zurückgibt. Probieren Sie einfach easy_install-ing simplejson in Ihrer Umgebung aus und prüfen Sie, ob dies funktioniert. Es hat für mich getan.

3
ducu

Verwenden Sie einfach pickle anstelle von json für das Abladen und Laden 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 (Strings und Ganzzahlen werden korrekt verarbeitet):

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

Python2 & 3 mit Hook unterstützen (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'}
1
abarik

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 auch für die typsichere JSON-Konvertierung benötigt - json.dump () würde alle Nicht-Literale wie Python-Objekte unterstützen. Konvertiert Dikt-Indizes jedoch nicht.

# 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
1
mario

Ich habe Wells '_parse_json () neu geschrieben, um Fälle zu behandeln, bei 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
0
darnmarshall

Dies ist zu spät, aber ich habe diesen rekursiven Zaubernden gebaut. Es funktioniert für meine Bedürfnisse und ich denke, es ist relativ vollständig. Es kann dir 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.

0
Wells

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

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

Ich könnte die oben vorgeschlagene byteify-Funktion verwenden, indem ich die Zeichenfolge mit ast.literal_eval(myStringDict) in ein dict-Objekt konvertiere.

0
narko

Check out this Antwort auf eine ähnliche Frage wie diese, die das sagt

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

Versuchen Sie dies beispielsweise:

print mail_accounts[0]["i"]

Sie werden kein u sehen.

0
kunal

Bei Python 3.6 stoße ich manchmal immer noch auf dieses Problem. Wenn Sie zum Beispiel eine Antwort von einer REST - API erhalten und den Antworttext in JSON laden, erhalte ich immer noch die Unicode-Zeichenfolgen.

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

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

Performance-Overhead 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)
0
Red Pill