Is using Python `isinstance` ever right?
I think I'd change it to be more like:
PLACEABLE_TYPES = [ Dirt ]
if isinstance(clickedblock, PLACEABLE_TYPES):
place the block
else:
don't place the block
but the idea in the comments of:
if clickedblock.is_placeable(that_place):
place the block
else:
don't place the block
also has merit.
I learned the hard way against using it. The problem is that the outcome is sensitive to how the class definitions were imported:
- in the place where the object was instantiated
- in the place where the
isinstance
test is performed
If one import was relative and the other absolute - the check will fail.
Essentially it'll be like checking on equality between SomeClass
vs somepackage.SomeClass
. It doesn't even matter that they come from the same file and so on. Also, there will be a similar outcome if you somehow have both the root directory and somepackage
directory in your PYTHONPATH
- then an absolute-styled import could denote a path from either of the "source roots" so two different absolute-styled imports would result in failing instance checks.
One could argue about how good practices would anyway prevent that from happening but good practices are also largely about not taking chances. In that spirit I prefer to put some abstract method in a common ancestor class so that I can later rely on how things quack rather than on what the interpreter believes them to be.
In Java each class resolves to its fully qualified class name. These are unique within a program and tests for instances are a breeze. In Python these can be slippery.
Your example seems like a legitimate use case of isinstance()
.
It's not that isinstance()
is bad, often polymorphism can be used for the same purpose (which results in cleaner code in where the class is used).
But sometimes, isinstance()
is what you need. For example, the pythonic way of detecting whether a variable is string or not is isinstance(var, basestring)
.