Bir değişkenin Python'da sözlük olup olmadığını nasıl kontrol edebilirim?


214

Bir değişkenin python'da sözlük olup olmadığını nasıl kontrol edersiniz?

Örneğin, bir sözlük bulana kadar sözlükteki değerler arasında döngü yapmasını istiyorum. Ardından, bulduğu ile döngü yapın:

dict = {'abc': 'abc', 'def': {'ghi': 'ghi', 'jkl': 'jkl'}}
for k, v in dict.iteritems():
    if ###check if v is a dictionary:
        for k, v in v.iteritems():
            print(k, ' ', v)
    else:
        print(k, ' ', v)

Ayrıca stackoverflow.com/questions/378927/… (yukarıdakinin kopyası olarak işaretlenmiştir).
NPE


40
Hayır, aynı soru değil. Bu sorunun ve burada listelenen diğer soruların cevabı büyük ölçüde aynı bilgileri içermektedir. Ancak "Bir değişkenin python'da sözlük olup olmadığı nasıl kontrol edilir?" Cevabı "type () veya isinstance () kullanın, bu da yeni bir soruya yol açar, bu da type () ve isinstance () arasındaki farkın ne olduğudur. . Ancak ilk soruyu soran kişi, ilk soru cevaplanana kadar bunu bilemez. Ergo, sitenizdeki sorunuzu ararken önemli olan farklı sorular.

13
@Mbakeranalecta katılıyorum Buraya "Python'da bir sözlük bir değişken mi kontrol edilir?" Sorusunun cevabını aramaya geldim. ve "Python'da isinstance () ve type () arasındaki farklar" konusundaki cevabımı asla düşünemezdim.
lodebari

5
Bir değişkenin özellikle sözlük olup olmadığını kontrol etmek için muhtemelen kullanmalısınız isinstance(v, collections.abc.Mapping). Başka bir deyişle, bu "isinstance () ve type () arasındaki farkların tam bir kopyası değildir.
Josh Kelley

Yanıtlar:


279

Alt sınıfa sahip olsaydınız işe yarayacak olanı kullanabilir if type(ele) is dictveya kullanabilirsiniz :isinstance(ele, dict)dict

d = {'abc':'abc','def':{'ghi':'ghi','jkl':'jkl'}}
for ele in d.values():
    if isinstance(ele,dict):
       for k, v in ele.items():
           print(k,' ',v)

70
Genel soruya doğru cevap çünkü bu cevabı aşağı olarak: isinstance(ele, collections.Mapping). Şunun için çalışır dict(), collections.OrderedDict()ve collections.UserDict(). Sorudaki örnek, Padriac'ın cevabının işe yaraması için yeterince spesifik, ancak genel durum için yeterince iyi değil.
Alexander Ryzhov

3
Bu cevabı reddettim, çünkü eğer çağıracaksanız ele.items()neden tipi kontrol ediyorsunuz? EAFP / ördek yazarak burada çalışıyor, sadece sarın for k,v in ele.items()içinde try...except (AttributeError, TypeError). Özel duruma neden olursa, bilirsin elehiçbir vardır items... bir iterable vermesidir
cowbert

@Padraic Cunningham Varsayımsal uç durumunuz, "% 100 items()bir dikte değil" özel sınıf 1'inizin bir yöntem 2'ye sahip olmasını gerektirecektir. -tuple. Bu noktada özel nesneniz zaten bir diktenin yarısını zaten uygulamıştır. Listelenen kodun amaçları doğrultusunda, yalnızca iç içe öğenin koşullu genişlemesini önemsedik ve özel nesneniz bunu zaten uygular. (@Alexander Ryzhov'un çok genel olduğu için yorumunu eleştirmek ama şimdi genel bir dava açmak biraz ironik)
cowbert

1
@PadraicCunningham Başlangıçta Python karşıtı kalıplara aşina olmayan insanlara öğretmeyi tercih etmem. Python'da açık bir daktilo denetimi gerektiren çok az kullanım durumu vardır - bunların çoğu başlamak için kötü bir uygulamayı devralmaktan kaynaklanır ('tanrı nesnesi, standart kütüphane / dil yapılarını geçersiz kılmak, vb.) Orijinal sorunun kendisi bir XY problemidir. OP'nin tipini neden kontrol etmesi gerekiyor? Çünkü kodlarına göre gerçekten yapmak istedikleri şey, koleksiyonlarındaki bir öğenin bir koleksiyon gibi davranıp davranmadığını kontrol etmektir ( items()iç içe yinelenebilir bir sonuç veren uygulamalar ).
cowbert

4
@AlexanderRyzhov Neden bu yaklaşımı bir cevap olarak yayınlamıyorsunuz? Josh Kelley'nin yukarıda yorumladığı gibi BTW collections.abc.Mapping, aynı olması için bir notun uygun olabileceğini, ancak collections.abcPython 3.3'ten önce mevcut olmadığını önerdi . collections.Mappingtakma ad Python 3.6'da hala mevcuttur, ancak belgelenmemiştir, bu yüzden muhtemelen tercih edilmelidir collections.abc.Maping.
Yushin Washio

5

Python'da bir değişkenin sözlük olup olmadığını nasıl kontrol edersiniz?

Bu mükemmel bir soru, ancak en çok oylanan cevabın kötü bir öneriye yol açması talihsiz bir durum type(obj) is dict.

(Ayrıca dictdeğişken adı olarak kullanmamanız gerektiğini unutmayın - bu yerleşik nesnenin adıdır.)

Başkaları tarafından içe aktarılacak ve kullanılacak kod yazıyorsanız, doğrudan dict yerleşimini kullanacaklarını varsaymayın - bu varsayımın kodunuzu daha esnek hale getirmesi ve bu durumda, programda hata yapmayacak kolayca gizlenebilecek hatalar yaratın .

Gelecekteki kullanıcılar için doğruluk, sürdürülebilirlik ve esneklik amacıyla, daha esnek, deyimsel ifadeler olduğunda kodunuzda asla daha az esnek, tek yönlü ifadeler olmamasını şiddetle öneririm.

isnesne kimliği için bir testtir . Kalıtımı desteklemez, herhangi bir soyutlamayı desteklemez ve arabirimi desteklemez.

Bu yüzden birkaç seçenek sunacağım.

Destekleyici miras:

Kullanıcıların kendi dict alt sınıfını veya tedarik için izin verir, çünkü bu, ben yapacak ilk öneri OrderedDict, defaultdictya Counterkoleksiyonları modülü dan:

if isinstance(any_object, dict):

Ancak daha esnek seçenekler de var.

Destekleyici soyutlamalar:

from collections.abc import Mapping

if isinstance(any_object, Mapping):

Bu, kodunuzun kullanıcısının herhangi bir alt sınıfını da içeren dictve yine de doğru davranışı elde eden soyut bir Eşleme'nin kendi özel uygulamasını kullanmasına izin verir .

Arayüzü kullanın

OOP tavsiyesini, "bir arayüze program" ifadesini sık sık duyarsınız.

Bu strateji Python'un polimorfizminden veya ördek tiplemesinden yararlanır.

Dolayısıyla, sadece belirli beklenen hataları yakalamak arayüzüne erişmek girişiminde ( AttributeErrordurumunda hiçbir yoktur .itemsve TypeErrordurumda itemsçağrılabilir değildir) makul bir yedek kullanımıyla - ve şimdi uygular arayüzü size onun öğeleri (not vereceğini herhangi sınıfta .iteritems()Python gitti 3):

try:
    items = any_object.items()
except (AttributeError, TypeError):
    non_items_behavior(any_object)
else: # no exception raised
    for item in items: ...

Belki de bunun gibi ördek yazmayı kullanmak çok fazla yanlış pozitifliğe izin vermede çok ileri gidebilir ve bu kod için hedeflerinize bağlı olabilir.

Sonuç

isStandart kontrol akışı türlerini kontrol etmek için kullanmayın . Arayüzü doğrudan kullanarak kullanın veya veya isinstancegibi soyutlamaları göz önünde bulundurun ve yazım denetiminden tamamen kaçınmayı düşünün.MappingMutableMapping


3

OP başlangıç ​​değişkenini dışarıda bırakmadı, bu nedenle tamlık için burada sözlük olarak öğeleri içerebilecek varsayılan bir sözlüğü işlemenin genel durumunun nasıl ele alınacağı.

Ayrıca yukarıdaki yorumlarda saf Python (3.8) sözlüğü test etmek için önerilen yolu takip ederek.

from collections.abc import Mapping

dict = {'abc': 'abc', 'def': {'ghi': 'ghi', 'jkl': 'jkl'}}

def parse_dict(in_dict): 
    if isinstance(in_dict, Mapping):
        for k, v in in_dict.items():
            if isinstance(v, Mapping):
                for k, v in v.items():
                    print(k, v)
            else:
                print(k, v)

parse_dict(dict)

dict.iteritems()Python 3'te mevcut değilse, dict.items()bunun yerine kullanmalısınız .
Arkelis

@Arkelis Hata! Bu bölümü kopyaladınız / yapıştırdınız, işaret ettiğiniz için teşekkürler - düzeltildi.
CodeMantle
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.