目的是实现某种插件框架,其中插件是同一基类(即A)的子类(即B)。基类使用标准导入加载,而子类使用知名包(即pkg)的路径从imp.load_module()加载。
pkg/
__init__.py
mod1.py
class A
mod2.py
class B(pkg.mod1.A)
这适用于真正的子类,即
# 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
但是在测试基类本身时出现了问题,
# 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
但是mod0.A和mod1.A实际上是同一个文件中的同一个类(pkg / mod1.py)。
此问题同时出现在python 2.7和3.2中。
现在问题是双重的,a)它是一个预期的功能还是issubclass()的bug,以及b)如何在不改变pkg内容的情况下摆脱这个?
答案 0 :(得分:5)
他们不是同一个班级。它们是使用相同的代码创建的,但由于您执行了两次代码(一次在导入中,一次在load_module中),您将获得两个不同的类对象。 issubclass
正在比较类对象的身份,它们是不同的。
编辑:因为你不能依赖issubclass
,一种可能的替代方法是在基类上创建一个将由派生类继承的唯一属性。该属性也将存在于类的副本中。然后,您可以测试该属性。
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
答案 1 :(得分:4)
由于我花了一些时间摆弄这个,我想我会分享我的解决方案:
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
当然,这只会真正检查子类继承自 CALLED parent_class
类,但出于我的目的(我大多数人怀疑),这很好。
注意:如果由于possible_child_class
[1:]
是parent_class的实例,则返回false。
答案 2 :(得分:1)
#!/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
这对我有用。我在sys.modules中按完整路径搜索类,如果找到则返回加载的实例。