如何在没有导入的情况下模仿Python模块? [英] How to mimic Python modules without import?

查看:134
本文介绍了如何在没有导入的情况下模仿Python模块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经尝试为Python 3开发一个模块扩展器工具,但我遇到了一些问题。

I’ve tried to develop a « module expander » tool for Python 3 but I've some issues.

这个想法如下:对于给定的Python脚本 main.py ,该工具生成功能相当的Python脚本 expanded_main.py ,方法是将每个import语句替换为导入模块的实际代码;这假设导入的Python源代码是可访问的。要以正确的方式完成工作,我使用Python的内置模块 ast 以及 astor ,允许将AST转储回Python源的第三方工具。这个导入扩展器的动机是能够将脚本编译成一个单字节码块,因此Python VM不应该负责导入模块(例如,这对于MicroPython非常有用)。

The idea is the following : for a given Python script main.py, the tool generates a functionally equivalent Python script expanded_main.py, by replacing each import statement by the actual code of the imported module; this assumes that the Python source code of the imported is accessible. To do the job the right way, I’m using the builtin module ast of Python as well as astor, a third-party tool allowing to dump the AST back into Python source. The motivation of this import expander is to be able to compile a script into one single bytecode chunk, so the Python VM should not take care of importing modules (this could be useful for MicroPython, for instance).

最简单的情况是声明:

from import my_module1 import *

要转换它,我的工具会查找文件 my_module1.py 和它用这个文件的内容替换import语句。然后, expanded_main.py 可以访问 my_module 中定义的任何名称,就像模块是以正常方式导入的一样。我不关心可能揭示诀窍的微妙副作用。另外,为了简化,我从导入my_module1导入a,b,c 处理作为上一次导入(带星号),而不关心可能的副作用。到目前为止一直很好。

To transform this, my tool looks for a file my_module1.py and it replaces the import statement by the content of this file. Then, the expanded_main.py can access any name defined in my_module, as if the module was imported the normal way. I don’t care about subtle side effects that may reveal the trick. Also, to simplify, I treat from import my_module1 import a, b, c as the previous import (with asterisk), without caring about possible side effect. So far so good.

现在,我的观点是这样的。你怎么能处理这种导入的风格:

Now here is my point. How could you handle this flavor of import:

import my_module2

我的第一个想法是通过创建一个与模块同名的类并复制缩进的Python文件的内容来模仿这个:

My first idea was to mimic this by creating a class having the same name as the module and copying the content of the Python file indented:

class my_module2:
    # content of my_module2.py
    …

这实际上适用于许多情况但是,遗憾的是,我发现这有几个小问题:其中一个是它失败的函数有一个体引用一个全局变量定义在模块。例如,考虑以下两个Python文件:

This actually works for many cases but, sadly, I discovered that this has several glitches: one of these is that it fails with functions having a body referring to a global variable defined in the module. For example, consider the following two Python files:

# my_module2.py 
g = "Hello"
def greetings():
    print (g + " World!")

# main.py
import my_module2
print(my_module2.g)
my_module2.greetings()

执行时, main.py 打印HelloHello World!。现在,我的扩展器工具将生成:

At execution, main.py prints "Hello" and "Hello World!". Now, my expander tool shall generate this:

# expanded_main.py
class my_module2:
    g = "Hello"
    def greetings():
        print (g + " World!")
print(my_module2.g)
my_module2.greetings()

执行 expanded_main.py 时,第一个打印语句就可以了(Hello)但是greetings函数引发了一个异常: NameError:name'g'未定义
模块中的

At execution of expanded_main.py, the first print statement is OK ("Hello") but the greetings function raises an exception: NameError: name 'g' is not defined. What happens actually is that


  • my_module2 code>, g 是一个全局变量,

  • my_module2 g 是一个类变量,应该称为 my_module2.g

  • in the module my_module2, g is a global variable,
  • in the class my_module2, g is a class variable, which should be referred as my_module2.g.

my_module2.py中定义函数,类......时会发生其他类似的副作用并且你想在其他函数,类,......中引用它们相同的 my_module2.py

Other similar side effects happens when you define functions, classes, … in my_module2.py and you want to refer to them in other functions, classes, … of the same my_module2.py.

知道如何解决这些问题吗?

除了类之外,是否还有其他允许模仿的Python结构一个模块?

最后注意事项:我知道该工具应该注意1°的嵌套导入(递归),2°可能的多次导入相同的模块。我不希望在这里讨论这些主题。

Final note: I’m aware that the tool should take care 1° of nested imports (recursion), 2° of possible multiple import of the same module. I don't expect to discuss these topics here.

推荐答案

您可以在一个范围内执行模块的源代码。 function ,特别是实例方法。然后可以通过在相应的类上定义 __ getattr __ 并保留初始函数的副本 locals()。以下是一些示例代码:

You can execute the source code of a module in the scope of a function, specifically an instance method. The attributes can then be made available by defining __getattr__ on the corresponding class and keeping a copy of the initial function's locals(). Here is some sample code:

class Importer:
    def __init__(self):

        g = "Hello"

        def greetings():
            print (g + " World!")

        self._attributes = locals()

    def __getattr__(self, item):
        return self._attributes[item]


module1 = Importer()
print(module1.g)
module1.greetings()

嵌套导入通过以相同的方式替换它们来自然处理导入程序的实例。重复导入也不应该是一个问题。

Nested imports are handled naturally by replacing them the same way with an instance of Importer. Duplicate imports shouldn't be a problem either.

这篇关于如何在没有导入的情况下模仿Python模块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆