I cannot understand why isinstance function as second parameter need a tuple instead of some iterable?
isinstance(some_object, (some_class1, some_class2))
works fine, but
isinstance(some_object, [some_class1, some_class2])
raise a TypeError
I cannot understand why isinstance function as second parameter need a tuple instead of some iterable?
isinstance(some_object, (some_class1, some_class2))
works fine, but
isinstance(some_object, [some_class1, some_class2])
raise a TypeError
The reason seems to be "allowing only tuples is enough, it's simpler, it avoids the danger of some corner cases, and it seemed neater to the BDFL" (i.e. Guido). (Kudos to @Caleb for posting the key link in the comments.)
Here is an excerpt from this email conversation with Guido van Rossum that specifically addresses the case of other iterables for the isinstance function. (Click on the link for the complete conversation.)
On Thu, Jan 2, 2014 at 1:37 PM, James Powell wrote:
This is driven by a real-world example wherein a large number of prefixes stored in a set, necessitating:
any('spam'.startswith(c) for c in prefixes) # or 'spam'.startswith(tuple(prefixes))Neither of these strikes me as bad. Also, depending on whether the set of prefixes itself changes dynamically, it may be best to lift the tuple() call out of the startswith() call.
...
However, .startswith doesn't seem to be the only example of this, and the other examples are free of the string/iterable ambiguity:
isinstance(x, {int, float})But this is even less likely to have a dynamically generated argument.
And there could still be another ambiguity here: a metaclass could conceivably make its instances (i.e. classes) iterable.
It is exacly as it should behave, according to the docs: https://docs.python.org/3/library/functions.html#isinstance
If classinfo is a tuple of type objects (or recursively, other such tuples), return true if object is an instance of any of the types. If classinfo is not a type or tuple of types and such tuples, a TypeError exception is raised.
Because a string is also "some iterable". So you could write:
isinstance(some_object, 'foobar')
and it would check if some_object is an instance of f, o, b, a or r.
This wouldn't work obviously, so isinstance would need to check if the second argument is not a string. Since isinstance needs to do a type check, it might as well make sure the second argument is always a tuple.
Because this is the way the language was designed...
When you write code that can accept more that one type, it is easier to have fixed types that you can directly test than using duck typing. For example as strings are iterable, when you want to accept either a string of a sequence of strings you must first test for the string type.
Here I can imagine no strong reason for limiting to the tuple type, but no strong reason either to extend it to any sequence. You could try to propose it on the python-ideas list.
At a high level need a container type for isinstance checks, so you have tuples, lists, sets, and dicts for built-in containers. Most likely, they decided on tuple over a set because the expected use case for isinstance is a small number of types, and a tuple is faster to check for containment of than compared to a set.
Mutability really isn't a consideration. If they really needed immutability, they could have just re-wrapped the iterable into a tuple before processing.