変数がPythonの辞書かどうかを確認するにはどうすればよいですか?


214

変数がPythonの辞書であるかどうかをどのように確認しますか?

たとえば、辞書が見つかるまで、辞書の値をループ処理します。次に、見つかったループをループします。

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)

また、stackoverflow.com / questions / 378927 /…(上記のものの複製としてマークされています)。
NPE 2014


40
いいえ、同じ質問ではありません。この質問およびここにリストされている他の質問への回答には、実質的に同じ情報が含まれています。しかし、「変数がPythonのディクショナリかどうかを確認する方法」に対する答えは「type()またはisinstance()を使用する」であり、type()とisinstance()の違いは何かという新しい質問につながります。 。しかし、最初の質問をする人は、最初の質問が答えられるまでそれをおそらく知ることができません。エルゴ、さまざまな質問。サイトで質問を探しているときに重要です。

13
@mbakeranalectaに同意します。「変数はPythonのディクショナリかどうかを確認する方法」という質問に対する答えを探してここに来ました。そして、私は自分の答えを「Pythonでのisinstance()とtype()の違い」に見ようとは思わなかったでしょう。
lodebari

5
変数が特に辞書かどうかを確認するには、おそらくを使用する必要がありますisinstance(v, collections.abc.Mapping)。つまり、これは「isinstance()とtype()の違い」の完全な複製ではありません。
Josh Kelley

回答:


279

あなたが使用するif type(ele) is dictisinstance(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
一般的な質問に対する正しい答えは次のとおりであるため、私はこの回答に反対票を投じましたisinstance(ele, collections.Mapping)。それはのために働くdict()collections.OrderedDict()collections.UserDict()。質問の例は、パドリアックの答えが機能するのに十分具体的ですが、一般的なケースには十分ではありません。
Alexander Ryzhov

3
私がこの回答に反対票を投じたのは、それを呼び出すつもりであれば、ele.items()なぜタイプをチェックするのですか?EAFP /ダックタイピングがここに働く、ちょうどラップfor k,v in ele.items()の中でtry...except (AttributeError, TypeError)。例外が発生した場合、eleitems
イテラブル

@Padraic Cunninghamあなたの架空のエッジケースでは、 "dictでない100%"カスタムクラス1. items()メソッドがあった2.たまたまiterableが生成された3. iterableの各要素が2として表される-タプル。この時点で、カスタムオブジェクトはすでに辞書の半分を実装しています。リストされたコードの目的のために、ネストされた要素の条件付き展開のみを考慮し、カスタムオブジェクトはすでにそれを実装しています。(@Alexander Ryzhovのコメントが一般的すぎると非難するが、今や一般的なケースを提起するのは少し皮肉なことです)
カウバート

1
@PadraicCunningham私は、Pythonアンチパターンにあまり慣れていない人には、そもそも教えたくない。明示的な型チェックを必要とする Pythonのユースケースはほとんどありません-ほとんどは、最初から悪い実装を継承することから生じます(「神オブジェクト」、標準ライブラリ/言語構成のオーバーライドなど)。元の問題はそれ自体がXY問題です。なぜOPはタイプをチェックする必要があるのですか?彼らのコードによると、彼らが本当にやりたいことは、コレクション内のアイテムがコレクションのように動作するかどうかをチェックすることです(items()ネストされた反復可能オブジェクトを生成する実装)。
カウバート

4
@AlexanderRyzhovそのアプローチを回答として投稿してみませんか?ところで、Josh Kelley が上記のコメントで指摘しているようにcollections.abc.Mapping、それらは同じであるというメモが適切かもしれませんが、collections.abcPython 3.3以前では利用できません。collections.MappingエイリアスはPython 3.6でも引き続き利用できますが、ドキュメント化されていないため、おそらくこちらをお勧めしcollections.abc.Mapingます。
鷲尾

3

OPは開始変数を除外しなかったため、ここで完全を期すために、辞書としてアイテムを含む可能性がある想定される辞書を処理する一般的なケースを処理する方法を示します。

また、上記のコメントで辞書をテストするための純粋なPython(3.8)推奨方法に従います。

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には存在しませんdict.items()。代わりに使用してください。
アルケリス

@Arkelis Oops、その部分をコピー/貼り付けたところ、指摘してくれてありがとう-今すぐ修正。
CodeMantle

3

変数がPythonの辞書であるかどうかをどのように確認しますか?

これは素晴らしい質問ですが、最も賛成された回答が不十分な推奨でリードされているのは残念ですtype(obj) is dict

dict変数名としても使用しないでください-組み込みオブジェクトの名前です。)

他の人がインポートして使用するコードを記述している場合は、組み込みのdictを直接使用することを想定しないでください。この推定により、コードの柔軟性が失われ、この場合、プログラムにエラーを発生させない、簡単に隠れたバグが作成されます。 。

将来のユーザーの正確性、保守性、柔軟性の目的で、より柔軟で慣用的な式がある場合は、コード内で柔軟性が低く、慣用的な式を使用しないことを強くお勧めします。

isオブジェクトの同一性のテストです。継承、抽象化、インターフェースはサポートしていません。

だから私はいくつかのオプションを提供します。

継承のサポート:

それは、ユーザーが辞書の独自のサブクラスを供給することができるため、またはこれは、私がなるだろう最初の勧告であるOrderedDictdefaultdictまたはCounterコレクションモジュールから:

if isinstance(any_object, dict):

しかし、さらに柔軟なオプションがあります。

抽象化のサポート:

from collections.abc import Mapping

if isinstance(any_object, Mapping):

これにより、コードのユーザーは、抽象マッピングの独自のカスタム実装を使用できます。これには、のサブクラスも含まれdict、正しい動作が得られます。

インターフェースを使用する

OOPのアドバイスである「インターフェイスへのプログラム」をよく耳にします。

この戦略は、Pythonのポリモーフィズムまたはダックタイピングを利用します。

だから、特定の期待のエラーをキャッチし、インターフェイスにアクセスしようとする(AttributeError場合に何もありません.itemsし、TypeError場合にitems呼び出すことはできません)合理的な代替と-そして、今実装は、インターフェースはあなたにその項目を(ノートが与えることをことを、任意のクラス.iteritems()のPythonでなくなっています3):

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

おそらく、このようにダックタイピングを使用すると、誤検出が多すぎて許容できなくなる可能性があり、このコードの目的によっては、そうなる可能性があります。

結論

is標準の制御フローのタイプをチェックするために使用しないでください。を使用しisinstanceMappingまたはのような抽象化MutableMappingを検討し、インターフェースを直接使用して、型チェックを完全に回避することを検討してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.