Ada yang lebih mudah dibaca cara untuk memeriksa apakah kunci dimakamkan di sebuah dict ada tanpa memeriksa setiap tingkat secara mandiri?
Mari kita mengatakan bahwa saya perlu untuk mendapatkan nilai dalam objek yang terkubur (contoh diambil dari Wikidata):
x = s['mainsnak']['datavalue']['value']['numeric-id']
Untuk memastikan bahwa ini tidak berakhir dengan runtime error hal ini diperlukan untuk memeriksa setiap tingkat seperti:
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']
Cara lain yang bisa saya pikirkan untuk memecahkan masalah ini adalah bungkus ini menjadi mencoba menangkap
membangun yang saya rasakan adalah juga agak canggung untuk suatu tugas sederhana.
Saya mencari sesuatu seperti:
x = exists(s['mainsnak']['datavalue']['value']['numeric-id'])
yang mengembalikan True
jika semua tingkatan yang ada.
Untuk menjadi singkat, dengan Python anda harus percaya itu adalah mudah untuk meminta pengampunan dari izin
try:
x = s['mainsnak']['datavalue']['value']['numeric-id']
except KeyError:
pass
Berikut adalah bagaimana saya berurusan dengan nested dict kunci:
def keys_exists(element, *keys):
'''
Check if *keys (nested) exists in `element` (dict).
'''
if not isinstance(element, dict):
raise AttributeError('keys_exists() expects dict as first argument.')
if len(keys) == 0:
raise AttributeError('keys_exists() expects at least two arguments, one given.')
_element = element
for key in keys:
try:
_element = _element[key]
except KeyError:
return False
return True
Contoh:
data = {
"spam": {
"egg": {
"bacon": "Well..",
"sausages": "Spam egg sausages and spam",
"spam": "does not have much spam in it"
}
}
}
print 'spam (exists): {}'.format(keys_exists(data, "spam"))
print 'spam > bacon (do not exists): {}'.format(keys_exists(data, "spam", "bacon"))
print 'spam > egg (exists): {}'.format(keys_exists(data, "spam", "egg"))
print 'spam > egg > bacon (exists): {}'.format(keys_exists(data, "spam", "egg", "bacon"))
Output:
spam (exists): True
spam > bacon (do not exists): False
spam > egg (exists): True
spam > egg > bacon (exists): True
Itu lingkaran dalam diberi elemen
pengujian masing-masing tombol dalam urutan tertentu.
Saya lebih menyukai ini untuk semua variabel.mendapatkan('kunci', {})` metode yang saya temukan karena mengikuti EAFP.
Fungsi kecuali untuk disebut seperti: keys_exists(dict_element_to_test, 'key_level_0', 'key_level_1', 'key_level_n', ..)
. Setidaknya dua argumen yang diperlukan, elemen dan satu tombol, tetapi anda dapat menambahkan berapa banyak kunci yang anda inginkan.
Jika anda perlu menggunakan jenis peta, anda dapat melakukan sesuatu seperti:
expected_keys = ['spam', 'egg', 'bacon']
keys_exists(data, *expected_keys)
Mencoba/kecuali tampaknya paling pythonic cara untuk melakukan itu. Berikut fungsi rekursif harus bekerja (kembali jika Tidak ada salah satu tombol tidak ditemukan dalam dict):
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
Saya sarankan anda untuk menggunakan python-benedict
, padat python dict subclass dengan penuh keypath dukungan dan banyak utilitas metode.
Anda hanya perlu untuk cast yang ada dict:
s = benedict(s)
Sekarang anda dict telah penuh keypath dukungan dan anda dapat memeriksa apakah ada kunci di pythonic cara, menggunakan operator:
if 'mainsnak.datavalue.value.numeric-id' in s:
# do stuff
Di sini perpustakaan repositori dan dokumentasi: https://github.com/fabiocaccamo/python-benedict
Anda dapat menggunakan pydash
untuk memeriksa jika ada: http://pydash.readthedocs.io/en/latest/api.html#pydash.objects.has
Atau mendapatkan nilai (anda bahkan dapat mengatur default - untuk kembali jika doesn't ada): http://pydash.readthedocs.io/en/latest/api.html#pydash.objects.has
Berikut ini sebuah contoh:
>>> get({'a': {'b': {'c': [1, 2, 3, 4]}}}, 'a.b.c[1]')
2
Coba/kecuali dengan cara yang paling bersih, tidak ada kontes. Namun, hal ini juga dianggap sebagai pengecualian dalam IDE saya, yang menghentikan eksekusi saat debugging.
Selain itu, saya tidak suka menggunakan pengecualian dalam metode kontrol pernyataan, yang pada dasarnya adalah apa yang terjadi dengan try/catch.
Berikut ini beberapa solusi yang tidak menggunakan rekursi, dan mendukung nilai default:
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
Aku punya masalah yang sama dan baru-baru lib python muncul: https://pypi.org/project/dictor/ https://github.com/perfecto25/dictor
Jadi dalam kasus anda: `` dari dictor impor dictor
x = dictor(s, 'mainsnak.datavalue.nilai.numerik-id') ``
Catatan pribadi: Saya don't seperti 'dictor' nama, karena itu doesn't petunjuk apa yang sebenarnya. Jadi saya'm menggunakannya seperti:
dari dictor impor dictor sebagai ekstrak x = ekstrak(s, 'mainsnak.datavalue.nilai.numerik-id')
Tidak't datang dengan baik penamaan dari ekstrak
. Jangan ragu untuk komentar, jika anda datang dengan lebih layak penamaan. safe_get
, robust_get
didn't merasa benar untuk kasus saya.
Aku menulis data parsing perpustakaan yang disebut dataknead
untuk kasus-kasus seperti ini, pada dasarnya karena aku frustrasi oleh JSON Wikidata API kembali juga.
Dengan perpustakaan itu anda bisa melakukan sesuatu seperti ini
from dataknead import Knead
numid = Knead(s).query("mainsnak/datavalue/value/numeric-id").data()
if numid:
# Do something with `numeric-id`