3

Problem: I have to check that the a returned value is a Python dictionary.

Q1. Which of these options is the proper way to do this?

type(x) == dict

type(x) == type(dict)

isinstance(d, dict)

Then there are the other variants using is operator instead of ==.

Q2. Many people say that checking the type of an object is generally a bad practice, but regarding to my initial problem, do I have any other choice?

Community
  • 1
  • 1
Paolo
  • 20,112
  • 21
  • 72
  • 113
  • Do you need it to be a dictionary or do you need to access items on it? – GaretJax Aug 01 '11 at 23:29
  • And anyways, the question you linked already provides the answer. – GaretJax Aug 01 '11 at 23:30
  • @Garet I need to be a dictionary because I'll use it to .update another dict. – Paolo Aug 01 '11 at 23:31
  • @Garet I'm sorry, I missed [the right answer for me](http://stackoverflow.com/questions/707674/how-to-compare-type-of-an-object-in-python/707878#707878). Though, my Q2 is not covered. – Paolo Aug 01 '11 at 23:36
  • Fair enough, S.Lott answer is the right one in your case (I might get him an up vote despite our recent history... :D ) – GaretJax Aug 01 '11 at 23:37
  • 1
    If you ever do actually need to check type, the Python docs tell you to use `isinstance` not `type`, and says to use `isinstance` with abstract base classes (from collections, numbers, io) to see if an object supports a particular interface. – agf Aug 02 '11 at 00:05
  • "I need to be a dictionary because I'll use it to .update another dict." Except that isn't actually the case. Even something as weird as `x = {}; x.update(['hi'])` will work. Try reading `help(dict.update)`, and then see if you can guess what the result will be. – Karl Knechtel Aug 02 '11 at 01:52

3 Answers3

8

Q1. Which of these options is the proper way to do this?

Don't waste time on type checking.

It's error-prone because it's based on assumptions.

Q2. ... do I have any other choice?

Yes do this.

try:
    x.the_dict_operation()
except TypeError:
    # x was not the expected type for the operation
    raise # or whatever.

In most cases, this amounts to "do nothing".

Just write the code. If "somehow" a malicious sociopath uses the wrong type, it will just crash like it's supposed to.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • +1 a big thanks, now I really understand what "Duck typing" is about. – Paolo Aug 01 '11 at 23:37
  • This way I have to trust that x.the_dict_operation method still does what it was supposed to do (in my case a plain .update of another dictionary). Isn't this a potential problem? – Paolo Aug 01 '11 at 23:47
  • @Guandalino: since you're using the user-supplied dict to update your own dict, your own dict's `.update()` method is getting called. If you can't trust that... – kindall Aug 02 '11 at 00:54
  • Let it just crash and fix the code, instead of lots of checks. I think that is good practice. – neuront Aug 02 '11 at 01:26
  • 1
    @Guandalino: "This way I have to trust..." What's the alternative? Magical introspection to assert that "somehow" the code is bug-free, satisfies all the contract specifications in the all of the "require" and "assure" clauses in the original design? There's no possible way to do anything other than trust. – S.Lott Aug 02 '11 at 01:52
2

Rely on behaviour, not on actual type (see other answers).

Lot of objects can act like dictionaries, you don't want to force users of your function/API to use plain dicts, right?

On the pragmatic side:

>>> type({})
<type 'dict'>
>>> dict
<type 'dict'>
>>> type(dict)
<type 'type'>
>>> isinstance({}, dict)
True
>>> isinstance("", dict)
False
Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
1

Check for __getitem__ rather than verifying the type. If you really want to type-check, any is fine (well, except type(x) == type(dict), that will never be true for a dict instance). isinstance is probably the most standard way to do it.

Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
  • `__getitem__` doesn't have anything to do with dict. Lots of objects have `__getitem__` that aren't dicts. For what he's doing (checking if the object can be passed to `{}.update`), this is particularly wrong: there are objects which can be passed to that function which don't have `__getitem__`. He wants to check if the object is iterable. – Glenn Maynard Aug 02 '11 at 00:20
  • @Glenn It needs to be iterable such that the iterated-over elements are each iterable, such that there are 2 elements in each of those. :) – Karl Knechtel Aug 02 '11 at 01:54