4

Why are there so many different ways to test for a dictionary? And what would be the most modern way to test if an object is a dictionary?

adict = {'a': 1}

In [10]: isinstance(adict, types.DictType)
Out[10]: True

In [11]: isinstance(adict, types.DictionaryType)
Out[11]: True

In [12]: isinstance(adict, dict)
Out[12]: True

In [13]: isinstance(adict, collections.Mapping)
Out[13]: True

In [14]: isinstance(adict, collections.MutableMapping)
Out[14]: True
user2864740
  • 60,010
  • 15
  • 145
  • 220
Jacques René Mesrine
  • 46,127
  • 27
  • 66
  • 104
  • The same could be said of most built-in types in Python. – nneonneo Apr 26 '14 at 01:09
  • Either for legacy support or syntactic-sugar? – Mr. Polywhirl Apr 26 '14 at 01:11
  • 1
    The last three all test for different but related things. Why is it so surprising in a language where everything is an object which supports multiple inheritance that built-in types can test true for several variations of `isinstance`? – Two-Bit Alchemist Apr 26 '14 at 01:15
  • there are languages whose collections library is way more sophisticated and consists of far finer grained interfaces than Python's, for example Scala's `scala.collection` is an extreme (but nice) example. – Erik Kaplun Apr 26 '14 at 01:20
  • @user2864740: I think you changed the question title to something that the OP did not mean; it's a big difference to ask "what's the right way" and "why are there so many different ways". – Erik Kaplun Apr 26 '14 at 01:24
  • @ErikAllik Perhaps. The OP can revert it if he/she so wishes. I was working with the goal of eliminating the question begging an opinion. That being said, I agree that it does. I've added back in the original "title question" in the body itself. – user2864740 Apr 26 '14 at 01:26
  • I don't think the "why" is opinion based here; there are concrete reasons for the plurality of options and there's not much room for opinion. And I think the original question title was much more interesting/important. – Erik Kaplun Apr 26 '14 at 01:27

2 Answers2

10

types.DictType and types.DictionaryType are deprecated (well, removed in Python 3) aliases of dict.

collections.Mapping and collections.MutableMapping are Abstract Base Classes (ABCs) so they work with mappings that don't subclass from dict. Normally that makes them a better choice, although very occasionally the stricter typecheck will be helpful.

So basically, check against, in order

  • None of them, if possible (duck-type)

  • collections.Mapping if you don't need mutation

  • collections.MutableMapping if you do need mutation

  • dict if you need it to actually be a dict type (this should be rare)

  • types.DictType or types.DictionaryType if you want to support really old versions

Veedrac
  • 58,273
  • 15
  • 112
  • 169
  • 1
    For the sake of being explicit about what "*really old* versions" means - `isinstance(x, dict)` has worked since the introduction of new-style classes in Python 2.2, which was released in December 2001. – lvc Apr 26 '14 at 01:33
2

First, types.DictType, types.DictionaryType, and dict are all the same (the documentation effectively notes that the first two are aliases for dict).

The last two are abstract base classes, and will actually test True for objects that don't inherit from dict at all. These are used if you want to test if an object is dict-like, i.e. whether it implements the same sort of operations that dict would. They are slightly different: Mapping is for general mappings (that may be immutable), whereas MutableMapping is strictly for mappings that can be modified.

nneonneo
  • 171,345
  • 36
  • 312
  • 383