Хорошо; ИМО это грубая, волосатая, темная магия. Вы не должны использовать это, возможно когда-либо, но особенно не в производственном коде. Однако это любопытно, просто ради любопытства.
Вы можете написать собственный импортер, используя механизмы, описанные в PEP 302 и более подробно обсуждаемые в PyMOTW Дуга Хеллмана: Модули и импорт . Это дает вам инструменты для выполнения задуманной вами задачи.
Я реализовал такого импортера только потому, что мне было любопытно. По сути, для модулей, которые вы задаете с помощью переменной класса __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