好的; IMO 这是粗俗的、毛茸茸的、黑暗的魔法。您可能永远不应该使用它,但尤其是在生产代码中。然而,出于好奇的缘故,这有点有趣。
您可以使用PEP 302中描述的机制编写自定义导入器,并在 Doug Hellmann 的PyMOTW: Modules and Imports中进一步讨论。这为您提供了完成预期任务的工具。
我实现了这样一个导入器,只是因为我很好奇。本质上,对于您通过类变量指定的模块,它会在评估代码之前__chatty_for__
将自定义类型作为__metaclass__
变量插入到导入的模块__dict__
中。如果有问题的代码定义了自己的,那将替换进口商预先插入的代码。在仔细考虑它会对它们做什么之前,不建议将此导入器应用于任何模块。__metaclass__
我没有写过很多进口商,所以我在写这篇文章时可能做了一件或多件愚蠢的事情。如果有人注意到我在实施中遗漏的缺陷/极端情况,请发表评论。
源文件1:
# foo.py
class Foo: pass
源文件2:
# bar.py
class Bar: pass
源文件3:
# baaz.py
class Baaz: pass
和主要事件:
# chattyimport.py
import imp
import sys
import types
class ChattyType(type):
def __init__(cls, name, bases, dct):
print "Class init", name
super(ChattyType, cls).__init__(name, bases, dct)
class ChattyImporter(object):
__chatty_for__ = []
def __init__(self, path_entry):
pass
def find_module(self, fullname, path=None):
if fullname not in self.__chatty_for__:
return None
try:
if path is None:
self.find_results = imp.find_module(fullname)
else:
self.find_results = imp.find_module(fullname, path)
except ImportError:
return None
(f,fn,(suf,mode,typ)) = self.find_results
if typ == imp.PY_SOURCE:
return self
return None
def load_module(self, fullname):
#print '%s loading module %s' % (type(self).__name__, fullname)
(f,fn,(suf,mode,typ)) = self.find_results
data = f.read()
if fullname in sys.modules:
module = sys.modules[fullname]
else:
sys.modules[fullname] = module = types.ModuleType(fullname)
module.__metaclass__ = ChattyType
module.__file__ = fn
module.__name__ = fullname
codeobj = compile(data, fn, 'exec')
exec codeobj in module.__dict__
return module
class ChattyImportSomeModules(ChattyImporter):
__chatty_for__ = 'foo bar'.split()
sys.meta_path.append(ChattyImportSomeModules(''))
import foo # prints 'Class init Foo'
import bar # prints 'Class init Bar'
import baaz