如何在不导入的情况下模拟Python模块?
我曾尝试为Python 3开发一个«模块扩展器»工具,但我遇到了一些问题 其思想如下:对于给定的Python脚本如何在不导入的情况下模拟Python模块?,python,import,Python,Import,我曾尝试为Python 3开发一个«模块扩展器»工具,但我遇到了一些问题 其思想如下:对于给定的Python脚本main.py,该工具通过用导入模块的实际代码替换每个导入语句,生成功能等效的Python脚本expanded_main.py;这假设导入的Python源代码是可访问的。为了正确地完成这项工作,我使用了Python的内置模块ast,以及astor,这是一个允许将ast转储回Python源代码的第三方工具。这个导入扩展器的动机是能够将脚本编译成单个字节码块,因此Python VM不应该负
main.py
,该工具通过用导入模块的实际代码替换每个导入语句,生成功能等效的Python脚本expanded_main.py
;这假设导入的Python源代码是可访问的。为了正确地完成这项工作,我使用了Python的内置模块ast
,以及astor
,这是一个允许将ast转储回Python源代码的第三方工具。这个导入扩展器的动机是能够将脚本编译成单个字节码块,因此Python VM不应该负责导入模块(例如,这可能对MicroPython很有用)
最简单的情况是:
from import my_module1 import *
要对此进行转换,我的工具将查找一个文件my_module1.py
,并用该文件的内容替换导入语句。然后,expanded_main.py
可以访问my_module
中定义的任何名称,就好像模块是以正常方式导入的一样。我不在乎那些可能会泄露秘密的微妙的副作用。此外,为了简化,我将导入模块1导入a、b、c中的视为上一次导入(带星号),而不考虑可能的副作用。到目前为止还不错
这是我的观点。您如何处理这种进口风味:
import my_module2
我的第一个想法是通过创建一个与模块同名的类并复制缩进的Python文件的内容来模拟这一点:
class my_module2:
# content of my_module2.py
…
这实际上适用于许多情况,但遗憾的是,我发现这有几个小问题:其中之一是它在函数体引用模块中定义的全局变量时失败。例如,考虑下面两个Python文件:
# my_module2.py
g = "Hello"
def greetings():
print (g + " World!")
及
执行时,main.py
打印“Hello”
和“Hello World!”
。现在,我的扩展工具将生成以下内容:
# expanded_main.py
class my_module2:
g = "Hello"
def greetings():
print (g + " World!")
print(my_module2.g)
my_module2.greetings()
执行expanded_main.py
时,第一条打印语句是OK的(“Hello”
),但是问候语函数引发了一个异常:NameError:未定义名称“g”
。
实际上发生的是
- 在模块
my_module2
中,g
是一个全局变量
- 在类
my_module2
中,g
是一个类变量,它应该被称为my_module2.g
当您在my_module2.py
中定义函数、类等,并希望在相同my_module2.py
的其他函数、类等中引用它们时,会发生其他类似的副作用
你知道如何解决这些问题吗
除了类之外,还有其他Python构造允许模拟模块吗
最后一点注意:我知道该工具应该处理1°嵌套导入(递归),2°相同模块的可能多次导入。我不希望在这里讨论这些主题。您可以在函数范围内执行模块的源代码,特别是实例方法。然后,可以通过在相应的类上定义\uuu getattr\uuu
并保留初始函数的局部变量()
的副本来使用这些属性。以下是一些示例代码:
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()
通过使用Importer
的实例以相同的方式替换嵌套导入,可以自然地处理嵌套导入。重复导入也不应该是问题。@Ignacio:正如我在消息中所说的,这是Python 3;我已经在3.4和3.6中测试过了。我知道在Python2中,异常是不同的(“TypeError:unbound method greetings()必须以我的_module2实例作为第一个参数调用(而不是什么都没有)”,至少在Python2.6中是这样);目标是拥有一个自包含的脚本,该脚本本身可以编译成一个自包含的Python字节码文件。执行此操作不需要在运行时依赖Python importi逻辑。也不会访问文件系统。这对于资源受限的系统(例如微控制器上的MicroPython)可能很有用。如果您将库“出售”到应用程序本地的文件夹中(即不在网站包中
),您将获得90%的好处,并且不必围绕这个问题进行编码。您是否构建了这样一个工具(将外部代码嵌入到主脚本中) ? 也许您已经找到了另一个执行相同任务的工具?你愿意分享吗?谢谢!这很聪明,这正是我想要的。
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()