Issubclass () returns False in the same class imported from different paths

The goal was to implement some kind of plugin frame diagram, where plugins are subclasses (i.e. B) of the same base class (i.e. A). The base class is loaded with standard imports, while subclasses are loaded with imp.load_module () from the path of a known package (i.e. Pkg).

pkg/ __init__.py mod1.py class A mod2.py class B(pkg.mod1.A) 

This worked fine with real subclasses, i.e.

 # test_1.py import pkg from pkg import mod1 import imp tup = imp.find_module('mod2', pkg.__path__) mod2 = imp.load_module('mod2', tup[0], tup[1], tup[2]) print(issubclass(mod2.B, mod1.A)) # True 

But the problem arose while testing the base class itself,

 # test_2.py import pkg from pkg import mod1 import imp tup = imp.find_module('mod1', pkg.__path__) mod0 = imp.load_module('mod1', tup[0], tup[1], tup[2]) print(issubclass(mod0.A, mod1.A)) # False 

But mod0.A and mod1.A are actually the same class from the same file (pkg / mod1.py).

This problem occurs in both python 2.7 and 3.2.

Now the question is twofold: a) Is this the expected function or error issubclass () and b) How to get rid of this without changing the contents of pkg?

+6
source share
3 answers

They are not the same. They were created with the same code, but since you executed this code twice (once in import and once in load_module), you get two different class objects. issubclass compares the identities of class objects, and they are different.

Edit: since you cannot rely on issubclass , one of the possible alternatives is to create a unique base class attribute that will be inherited by derived classes. This attribute will exist on copies of the class. Then you can check the attribute.

 class A: isA = True class B(A): pass class C: pass def isA(aclass): try: return aclass.isA except AttributeError: return False print isA(A) True print isA(B) True print isA(C) False 
+5
source

Since I spent some time on this, I decided to share my solution:

 import inspect ... def inherits_from(child, parent_name): if inspect.isclass(child): if parent_name in [c.__name__ for c in inspect.getmro(child)[1:]]: return True return False print inherits_from(possible_child_class, 'parent_class') #True 

Of course, this only checks that the child class inherits from the CALLED parent_class class, but for my purpose (and most of them I suspect) this is normal.

Note: this returns false if possible_child_class is an instance of parent_class due to [1:] .

+3
source
 #!/usr/bin/env python import os import sys import pkg from pkg import mod1 import imp def smart_load_module(name, path): # get full module path full_path = os.path.abspath(os.path.join(path[0], name)) for module_name, module in sys.modules.items(): # skip empty modules and ones without actual file if not module or not hasattr(module, '__file__'): continue # remove extension and normalize path module_path = os.path.abspath(os.path.splitext(module.__file__)[0]) if full_path == module_path: return module # if not found, load standard way tup = imp.find_module(name, path) return imp.load_module(name, tup[0], tup[1], tup[2]) if __name__ == '__main__': mod00 = smart_load_module('mod1', pkg.__path__) print(issubclass(mod00.A, mod1.A)) # True tup = imp.find_module('mod1', pkg.__path__) mod0 = imp.load_module('mod1', tup[0], tup[1], tup[2]) print(issubclass(mod0.A, mod1.A)) # False 

This works for me. I look at the class in the full path in sys.modules and return the loaded instance if it is found.

+1
source

Source: https://habr.com/ru/post/920376/


All Articles