Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is using Python `isinstance` ever right?

I've got a 2D array of different blocks, all inheriting from Block. I want to check if the block that I clicked on is a Dirt type block, like this:

clickedblock = getClickedBlock()

if isinstance(clickedblock, Dirt):
    place a block

else:
    don't place a block

I've heard that isinstance is bad, and should be avoided because it creates forks in code. What times would isinstance be good to use?

Another more cumbersome solution for my problem would be to have a field of Block called 'id' and then check if it equals some constant that means Dirt. But that sounds quite bad and more prone for mistake than the simple isinstance.

like image 541
Name McChange Avatar asked Nov 29 '12 22:11

Name McChange


2 Answers

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).

like image 175
Imran Avatar answered Oct 15 '22 18:10

Imran


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.

like image 29
bawey Avatar answered Oct 15 '22 17:10

bawey