即时组装 Python 模块,动态导入
Assembling Python module on fly, dynamic import
我正在努力让自己熟悉 importlib
钩子。我想实现直接导入用其他语言编写的非 pythonic 文件并维护源映射的功能,因此使用行号提高 SyntaxError
s 仍会提供有意义的堆栈跟踪。
我加载外部文件的方法是组装 Pythonic 源代码,然后编译它并在所需的上下文中执行它。
我在文档中读到实施 importlib.abc.SourceLoader
似乎是我的选择 — 然而,唯一被调用的方法是 exec_module
。在那个阶段,据我所知,模块对象已经完全准备好了。那为什么不叫get_source
、get_data
、get_code
等呢?
我的存根实现:
import sys
import os
import importlib.abc
import importlib.machinery
class MyFinder(importlib.abc.MetaPathFinder):
def __init__(self):
pass
def find_spec(self, fullname, path, target=None):
print('find_spec', fullname, path, target)
# filename = '{}.npy'.format(fullname)
# if not os.path.exists(filename):
# return
if fullname != 'foobar':
return
filename = 'foobar://ponyworld/foo.py'
spec = importlib.machinery.ModuleSpec(
name = fullname,
loader = MyLoader(fullname, path, target),
origin = filename,
loader_state = 1234,
is_package = False,
)
return spec
class MyLoader(importlib.abc.SourceLoader):
def __init__(self, fullname, path, target):
pass
def get_data(self, path):
print('get_data', path)
def get_filename(self, fullname):
print('get_filename', fullname)
def path_stats(self, path):
print('path_stats', path)
def set_data(self, path, data):
print('set_data', path, data)
def get_code(self, fullname):
print('get_code', fullname)
def exec_module(self, module):
print('exec_module', module)
print(dir(module))
def get_source(self, fullname):
print('get_source', fullname)
def is_package(self, fullname):
print('is_package', fullname)
sys.meta_path.append(MyFinder())
# import fake module to see if it works
import foobar
我误解了文档并忽略了 importlib.abc.SourceLoader
已经为 get_code
、exec_module
、load_module
、get_source
和 is_package
提供了实现。只有在需要时才会覆盖这些,并且只有 get_data
和 get_filename
是所需的最小值。
我正在努力让自己熟悉 importlib
钩子。我想实现直接导入用其他语言编写的非 pythonic 文件并维护源映射的功能,因此使用行号提高 SyntaxError
s 仍会提供有意义的堆栈跟踪。
我加载外部文件的方法是组装 Pythonic 源代码,然后编译它并在所需的上下文中执行它。
我在文档中读到实施 importlib.abc.SourceLoader
似乎是我的选择 — 然而,唯一被调用的方法是 exec_module
。在那个阶段,据我所知,模块对象已经完全准备好了。那为什么不叫get_source
、get_data
、get_code
等呢?
我的存根实现:
import sys
import os
import importlib.abc
import importlib.machinery
class MyFinder(importlib.abc.MetaPathFinder):
def __init__(self):
pass
def find_spec(self, fullname, path, target=None):
print('find_spec', fullname, path, target)
# filename = '{}.npy'.format(fullname)
# if not os.path.exists(filename):
# return
if fullname != 'foobar':
return
filename = 'foobar://ponyworld/foo.py'
spec = importlib.machinery.ModuleSpec(
name = fullname,
loader = MyLoader(fullname, path, target),
origin = filename,
loader_state = 1234,
is_package = False,
)
return spec
class MyLoader(importlib.abc.SourceLoader):
def __init__(self, fullname, path, target):
pass
def get_data(self, path):
print('get_data', path)
def get_filename(self, fullname):
print('get_filename', fullname)
def path_stats(self, path):
print('path_stats', path)
def set_data(self, path, data):
print('set_data', path, data)
def get_code(self, fullname):
print('get_code', fullname)
def exec_module(self, module):
print('exec_module', module)
print(dir(module))
def get_source(self, fullname):
print('get_source', fullname)
def is_package(self, fullname):
print('is_package', fullname)
sys.meta_path.append(MyFinder())
# import fake module to see if it works
import foobar
我误解了文档并忽略了 importlib.abc.SourceLoader
已经为 get_code
、exec_module
、load_module
、get_source
和 is_package
提供了实现。只有在需要时才会覆盖这些,并且只有 get_data
和 get_filename
是所需的最小值。