Gibt es eine besser lesbare Möglichkeit, um zu überprüfen, ob ein in einem Diktat vergrabener Schlüssel vorhanden ist, ohne jede Ebene einzeln zu überprüfen?
Nehmen wir an, ich muss diesen Wert in einem vergrabenen Objekt erhalten (Beispiel aus Wikidata):
x = s['mainsnak']['datavalue']['value']['numeric-id']
Um sicherzustellen, dass dies nicht mit einem Laufzeitfehler endet, müssen Sie entweder jede Ebene wie folgt überprüfen:
if 'mainsnak' in s and 'datavalue' in s['mainsnak'] and 'value' in s['mainsnak']['datavalue'] and 'nurmeric-id' in s['mainsnak']['datavalue']['value']:
x = s['mainsnak']['datavalue']['value']['numeric-id']
Die andere Möglichkeit, dies zu lösen, besteht darin, dies in ein try catch
Konstrukt zu packen, das meiner Meinung nach für eine so einfache Aufgabe ebenfalls ziemlich umständlich ist.
Ich suche so etwas wie:
x = exists(s['mainsnak']['datavalue']['value']['numeric-id'])
Dies wird zurückgegeben, True
wenn alle Ebenen vorhanden sind.
try except
Anweisungen hinterlassen ein ziemliches Aufblähen.try-except
Logik machen und dies einfach jedes Malif type(element) is not dict
zuif not isinstance(element, dict)
. Auf diese Weise funktioniert es auch für Typen wie OrderedDict.Sie können
.get
mit Standardeinstellungen verwenden:s.get('mainsnak', {}).get('datavalue', {}).get('value', {}).get('numeric-id')
Dies ist jedoch mit ziemlicher Sicherheit weniger klar als die Verwendung von try / Except.
quelle
get
als Standardwert angeben, es könnte einfach der Wert von seins['mainsnak']['datavalue']['value']['numeric-id']
.get
) (keines ist mein Fall), wird dies mit'NoneType' object has no attribute 'get'
oder einem beliebigen Typ enden, den Sie dort haben.Try / Except scheint der pythonischste Weg zu sein, dies zu tun.
Die folgende rekursive Funktion sollte funktionieren (gibt None zurück, wenn einer der Schlüssel im Diktat nicht gefunden wurde):
def exists(obj, chain): _key = chain.pop(0) if _key in obj: return exists(obj[_key], chain) if chain else obj[_key] myDict ={ 'mainsnak': { 'datavalue': { 'value': { 'numeric-id': 1 } } } } result = exists(myDict, ['mainsnak', 'datavalue', 'value', 'numeric-id']) print(result) >>> 1
quelle
Sie können verwenden
pydash
, um zu überprüfen, ob vorhanden: http://pydash.readthedocs.io/en/latest/api.html#pydash.objects.hasOder rufen Sie den Wert ab (Sie können sogar den Standardwert festlegen - um ihn zurückzugeben, wenn er nicht vorhanden ist): http://pydash.readthedocs.io/en/latest/api.html#pydash.objects.has
Hier ist ein Beispiel:
>>> get({'a': {'b': {'c': [1, 2, 3, 4]}}}, 'a.b.c[1]') 2
quelle
Der Versuch / außer Weg ist der sauberste, kein Wettbewerb. Es zählt jedoch auch als Ausnahme in meiner IDE, die die Ausführung während des Debuggens anhält.
Darüber hinaus mag ich es nicht, Ausnahmen als methodeninterne Steueranweisungen zu verwenden, was im Wesentlichen mit try / catch geschieht.
Hier ist eine kurze Lösung, die keine Rekursion verwendet und einen Standardwert unterstützt:
def chained_dict_lookup(lookup_dict, keys, default=None): _current_level = lookup_dict for key in keys: if key in _current_level: _current_level = _current_level[key] else: return default return _current_level
quelle
current_level[key]
kann auf einen Wert und nicht auf ein inneres Diktat verweisen. Wenn Sie dies verwenden, achten Sie darauf, dasscurrent_level
es sich nicht um einen String, einen Float oder etwas anderes handelt.Python 3.8 +
dictionary = { "main_key": { "sub_key": "value", }, } if sub_key_value := dictionary.get("main_key", {}).get("sub_key"): print(f"The key 'sub_key' exists in dictionary[main_key] and it's value is {sub_key_value}") else: print("Key 'sub_key' doesn't exists")
quelle
Ich empfehle Ihnen
python-benedict
, eine solide Python-Diktat-Unterklasse mit vollständiger Schlüsselpfadunterstützung und vielen Dienstprogrammmethoden zu verwenden.Sie müssen nur Ihr bestehendes Diktat umsetzen:
Jetzt unterstützt Ihr Diktat die vollständige Schlüsselpfadunterstützung und Sie können mithilfe des Operators in überprüfen, ob der Schlüssel pythonisch vorhanden ist :
if 'mainsnak.datavalue.value.numeric-id' in s: # do stuff
Hier das Bibliotheksrepository und die Dokumentation: https://github.com/fabiocaccamo/python-benedict
Hinweis: Ich bin der Autor dieses Projekts
quelle
Ich hatte das gleiche Problem und kürzlich tauchte die Python-Bibliothek auf:
https://pypi.org/project/dictor/
https://github.com/perfecto25/dictor
Also in deinem Fall:
from dictor import dictor x = dictor(s, 'mainsnak.datavalue.value.numeric-id')
Persönliche Anmerkung:
Ich mag den Namen eines Diktors nicht, da er nicht andeutet, was er tatsächlich tut. Also benutze ich es wie folgt:
from dictor import dictor as extract x = extract(s, 'mainsnak.datavalue.value.numeric-id')
Könnte nicht besser benannt werden als
extract
. Fühlen Sie sich frei zu kommentieren, wenn Sie eine brauchbarere Benennung finden.safe_get
,robust_get
Fühlte sich nicht richtig für meinen Fall zu spüren.quelle
Ich habe eine Datenanalysebibliothek geschrieben, die für solche
dataknead
Fälle aufgerufen wurde , im Grunde genommen, weil ich von JSON frustriert war und die Wikidata-API ebenfalls zurückgibt.Mit dieser Bibliothek könnten Sie so etwas tun
from dataknead import Knead numid = Knead(s).query("mainsnak/datavalue/value/numeric-id").data() if numid: # Do something with `numeric-id`
quelle
Wenn Sie eine Zeichenfolgendarstellung des Objektpfads testen müssen, funktioniert dieser Ansatz möglicherweise für Sie:
def exists(str): try: eval(str) return True except: return False exists("lst['sublist']['item']")
quelle
Ein anderer Weg:
def does_nested_key_exists(dictionary, nested_key): exists = nested_key in dictionary if not exists: for key, value in dictionary.items(): if isinstance(value, dict): exists = exists or does_nested_key_exists(value, nested_key) return exists
quelle