8

As I write it, it seems almost surreal to me that I'm actually experiencing this problem.

I have a list of objects. Each of these objects are of instances of an Individual class that I wrote.

Thus, conventional wisdom says that isinstance(myObj, Individual) should return True. However, this was not the case. So I thought that there was a bug in my programming, and printed type(myObj), which to my surprise printed instance and myObj.__class__ gave me Individual!

>>> type(pop[0])
<type 'instance'>
>>> isinstance(pop[0], Individual) # with all the proper imports
False
>>> pop[0].__class__
Genetic.individual.Individual

I'm stumped! What gives?

EDIT: My Individual class

class Individual:
    ID = count()
    def __init__(self, chromosomes):
        self.chromosomes = chromosomes[:]    # managed as a list as order is used to identify chromosomal functions (i.e. chromosome i encodes functionality f)
        self.id = self.ID.next()

    # other methods
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241

2 Answers2

14

This error indicates that the Individual class somehow got created twice. You created pop[0] with one version of Instance, and are checking for instance with the other one. Although they are pretty much identical, Python doesn't know that, and isinstance fails. To verify this, check whether pop[0].__class__ is Individual evaluates to false.

Normally classes don't get created twice (unless you use reload) because modules are imported only once, and all class objects effectively remain singletons. However, using packages and relative imports can leave a trap that leads to a module being imported twice. This happens when a script (started with python bla, as opposed to being imported from another module with import bla) contains a relative import. When running the script, python doesn't know that its imports refer to the Genetic package, so it processes its imports as absolute, creating a top-level individual module with its own individual.Individual class. Another other module correctly imports the Genetic package which ends up importing Genetic.individual, which results in the creation of the doppelganger, Genetic.individual.Individual.

To fix the problem, make sure that your script only uses absolute imports, such as import Genetic.individual even if a relative import like import individual appears to work just fine. And if you want to save on typing, use import Genetic.individual as individual. Also note that despite your use of old-style classes, isinstance should still work, since it predates new-style classes. Having said that, it would be highly advisable to switch to new-style classes.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • `pop[0].__class__ is Genetic.individual.Individual` evaluates to `True`. – inspectorG4dget Oct 23 '12 at 21:08
  • 1
    But what does `pop[0].__class__ is Individual` evaluate to in your interactive Python session where `isinstance(pop[0], Individual)` evaluates to False? (I should have been more precise in my answer.) – user4815162342 Oct 23 '12 at 21:12
  • Yes, that evaluates to `False` – inspectorG4dget Oct 23 '12 at 21:18
  • Then keep reading the answer... where I work we stumbled upon that particular problem many times in both testing and production. – user4815162342 Oct 23 '12 at 21:19
  • That's some really weird behavior, but it seemed to fix it. Thanks for the explanation – inspectorG4dget Oct 23 '12 at 21:35
  • I encountered this when using `isinstance` in a jupyter notebook after issuing the [`autoreload 2`](https://ipython.org/ipython-doc/3/config/extensions/autoreload.html) magic (which under the hood uses `reload` of course). – stav Nov 26 '18 at 13:45
1

You need to use new-style classes that inherit from

class ClassName(object):
    pass

From your example, you are using old-style classes that inherit from

class Classname:
    pass

EDIT: As @user4815162342 said,

>>> type(pop[0])
<type 'instance'>

is caused by using an old-style class, but this is not the cause of your issues with isinstance. You should instead make sure you don't create the class in more than one place, or if you do, use distinct names. Importing it more than once should not be an issue.

bossylobster
  • 9,993
  • 1
  • 42
  • 61
  • Could you post an explanation as to why this fixes the error? Also, my code was working yesterday, so I'm also interested in any other explanations you may have – inspectorG4dget Oct 23 '12 at 20:55
  • Because inheritance doesn't work the same with old-style classes. With new-style classes, `isinstance` essentially checks `obj.__class__` and then recursively each superclass found in `obj.__class__.__bases__`. With old-style classes, this behavior is not guaranteed. If we could see your definition(s), we may be able to explain why not in your case. – bossylobster Oct 23 '12 at 21:00
  • This answer doesn't even attempt to explain why `isinstance` fails for the OP. Using new-style classes would fix the `obj.__class__` vs. `type(obj)` discrepancy, but not the problem observed with `isinstance`, which is at the focus of the question. – user4815162342 Oct 23 '12 at 21:15
  • This solution worked once. It failed on the second run. Weird – inspectorG4dget Oct 23 '12 at 21:18