【问题标题】:How do modules and scope interact when the same module is imported into the same environment multiple times?当同一个模块被多次导入同一个环境时,模块和作用域如何交互?
【发布时间】:2021-06-24 13:58:18
【问题描述】:

假设我们有模块 ABC,并且该模块 C 在模块范围内有一些变量 X

A 导入 B,后者(出于自身目的)导入 CA 也直接导入C

如果A 改变了C.X 的值,那会改变B 看到的C.X 的值吗?同样,如果B 更改其C.X 的值,是否会更改A 看到的值?

换句话说,当一个模块被多次导入同一个解释器上下文时,该模块命名空间中的可变变量是否有效地共享内存?

【问题讨论】:

  • 您在描述代码并要求我们编写它(无论是在物理上还是在我们的头脑中)。如果您实际编写代码,看看它做了什么,然后在这里询问您是否不明白发生了什么,您更有可能得到响应。
  • @BoarGules 我在问一个应该在语言规范中明确指定的理论问题,并且(如果不是)很可能在不同的实现中不一致。在本地尝试不会告诉我它在(比如说)2.x 和 3.x 之间是否不同,也不会告诉我它是否首先按照规范实现。

标签: python module scope


【解决方案1】:

如果A 更改C.X 的值,是否会更改B 看到的C.X 的值?

tl;dr

这取决于您如何导入X,以及X可变性

import C

如果AB 都使用import C 语句导入C 模块,则它们都可以访问和修改C.X。名称X 绑定到C 模块,AB 都可以访问该模块。示例:

C.py

X = 1

B.py

import C

def func():
     print(C.X)

A.py

import B
import C

C.X = 2
B.func()

运行A.py 打印2 - A 有效地修改了C 模块命名空间的X 属性,并且此更改在调用B 时反映在B 中。

from C import X

from _ import _ 语句从外部模块获取属性并将其绑定到当前模块。当模块AC 导入X 时,它只是将该值绑定到A 的命名空间。换句话说,在A 的命名空间中对X 的更改不会反映对B.XC.X 的更改。示例:

C.py

X = 1

B.py

from C import X

def func():
     print(X)

A.py

import B
from C import X

X = 2
B.func()

运行A.py 打印1,因为B.func() 将打印存储在B.X 的值,而我们只修改了A.X

如果X 是可变的怎么办?

如果X 是可变的(列表、字典、用户定义的类或实例等),那么你如何导入它并不重要——在任何模块中改变导入的对象都会传播到所有模块。示例:

C.py

X = {}  # mutable object (empty dictionary)

B.py

from C import X

def func():
     print(X)

A.py

import B
import C

C.X['key'] = 'value'
B.func()

运行A.py 打印{'key': 'value'}。尽管A 使用了import _ 语句,而B 使用了from _ import _ 语句,但我们已经有效地修改了同一个对象。对于任何可变对象都是如此,无论 AB 如何导入它。

【讨论】:

  • 需要强调的是,对象的类型不影响导入的语义...不可变对象只是不可变 .
【解决方案2】:

一个模块只能加载到内存中一次。 sys.modules 包含一个主列表,其中列出了在整个整个程序中加载的模块以及它们所在的位置。

如果多个文件import同一个模块,它会被加载到内存中一次并缓存在sys.modules中,然后后续的导入尝试只是获取缓存的版本。

因此,同一个模块的所有导入(无论文件如何)都指向同一个内存块。因此,在该模块中修改的任何内存都将在整个程序中持续存在。


您可以通过将sys.stdoutsys.stderr 重新分配给文件流而不是输出流来实际测试这一点,这将修改整个程序其余部分中每个print() 语句的打印和错误输出。 (要设置它们,您可以使用sys.__stdout__sys.__stderr__,它们也可以类似地重新定义,但不应该)。这表明程序的每个部分都使用sys 模块的相同实例

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-05
    相关资源
    最近更新 更多