本文介绍了动态组装Python模块,动态导入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使自己熟悉 importlib 挂钩.我想实现一种功能,以直接导入用其他语言编写的非pythonic文件并维护源映射,因此使用行号引发 SyntaxError 仍然会提供有意义的堆栈跟踪.

I'm trying to get myself familiar with importlib hooks. I want to implement an ability to directly import non-pythonic files written in other language, and maintain source maps, so raising SyntaxErrors with line numbers will still give meaningful stacktraces.

我加载外部文件的方法是组装Pythonic源代码,然后对其进行编译并在所需的上下文中执行它.

My approach to loading foreign files is assembling Pythonic source, then compiling it and executing it in the desired context.

我在文档中已经读到,实现 importlib.abc.SourceLoader 似乎是我的选择-但是,唯一被调用的方法是 exec_module .据我所知,在那个阶段,模块对象已经准备就绪.那么为什么没有调用 get_source get_data get_code 和其他代码?

I've read in the documentation that implementing importlib.abc.SourceLoader seems to be my choice — however, the only method that is being called is exec_module. At that stage, to my understanding, module object is fully ready. So why are get_source, get_data, get_code and others are not called?

我的存根实现:

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 是必需的最小值.

I misunderstood documentation and overlooked that importlib.abc.SourceLoader already provides implementations for get_code, exec_module, load_module, get_source and is_package. Those are to be overridden only in need, and only get_data and get_filename are the required minimum.

这篇关于动态组装Python模块,动态导入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 22:45