限制.py文件中可从其他地方导入的类
我有一个Python源文件,里面定义了一个类,并且从另一个模块导入了一个类。大致结构是这样的:
from parent import SuperClass
from other import ClassA
class ClassB(SuperClass):
def __init__(self): pass
我想做的是在这个模块里查找所有定义的类,只找到ClassB,而忽略ClassA。ClassA和ClassB都是从SuperClass继承来的。
这样做的原因是我有一个插件目录,这些插件在运行时加载。我通过检查每个.py文件,获取所有继承自SuperClass的插件类。在这个特定的情况下,ClassB依赖于插件ClassA来完成一些工作,而ClassA并不依赖于ClassB。问题是,当我从目录加载插件时,我得到了两个ClassA的实例,一个来自ClassA的文件,另一个来自ClassB的文件。
对于包,有一种方法:
__all__ = ['module_a', 'module-b']
可以明确列出可以导入的模块,但这需要在__init__.py
文件中,而每个插件都是一个.py文件,而不是一个独立的目录。
那么问题是:我能否限制对.py文件中类的访问,还是必须把每个类都放在一个有自己init文件的目录里?或者,有没有其他聪明的方法可以区分这两个类?
1 个回答
你说的是“对于包有这样的处理方式……”。其实,这种方式适用于每一个模块(__init__.py
也是一个模块,只是有些特别的含义)。在插件模块里使用 __all__
就可以了。
不过要记住:__all__
只是限制了你用 from xxxx import *
这种方式导入的内容;你仍然可以访问模块里的其他部分,而且用标准的Python导入方式是无法避免这一点的。
如果你使用某种主动检查的技术(比如探索模块里的命名空间,然后从中导入类),你可以检查这个类是否来自于和模块本身相同的文件。
你也可以实现自己的导入机制(比如使用 importlib
),但这样可能有点复杂……
补充一下:关于“检查类是否来自同一个模块”:
假设我有两个模块,mod1.py
:
class A(object):
pass
还有 mod2.py
:
from mod1 import A
class B(object):
pass
现在,如果我这样做:
from mod2 import *
我导入了 A
和 B
。但是……
>>> A
<class 'mod1.A'>
>>> B
<class 'mod2.B'>
正如你所看到的,这些类会带有它们来源的信息。实际上,你可以立即检查这一点:
>>> A.__module__
'mod1'
>>> B.__module__
'mod2'
利用这些信息,你可以很容易地区分它们。