问题描述
a = [1]
和
from dummy_module import a
print(f"a = {a},after first import")
a.append(3)
print(f"a = {a},after appending an element to list 'a'.")
from dummy_module import a
print(f"a = {a},after importing 'a' again from 'dummy_module'.") # NO! I want this to return 'a = 1' again!
这将返回
a = [1],after first import
a = [1,3],after appending an element to list 'a'.
a = [1],after importing 'a' again from 'dummy_module'.
我注意到变量a
通过import
显然是通过引用而不是通过值复制的,因为如果我在第一个a
之后修改import
更改a
中的dummy_module
。
我想按值(深层副本)而不是按引用(浅层副本)导入a
。我可以通过将a = deepcopy(a)
放在a.append(3)
之前解决此问题,但是在我从一个模块中导入多个变量的应用程序中,这变得很麻烦,因此我想避免这种方法。
我该如何解决?
解决方法
在Python中,未使用“按值传递”和“按引用传递”这两个术语,因为进行赋值时不会复制任何内容。
某些类型的对象具有与重新分配时“按值传递”相同的行为,因为它们是不可变的,这意味着通过创建一个全新的对象(保留旧的对象不变)来完成名称的重新分配。
您的情况如何?
import语句仅执行模块代码并进行一些名称绑定,但是第二次运行import语句时,代码a = [1]
语句不会再次执行,因为它具有已被module cache缓存。
我可以通过在{a.append(3)'之前放置
a = deepcopy(a)
来解决此问题。
之所以可行,是因为Deepcopy在将a
绑定到列表对象之前会创建一个新的列表对象,而使先前的对象保持不变(并由模块缓存进行缓存)。您需要对每个导入的名称执行类似的操作。
Quick Hack
可以通过在第二次导入完成之前在模块高速缓存上进行快速删除来再次重新初始化模块中的所有名称(此名称可能会导致错误代码)。这将强制import语句在进行绑定之前重新执行模块代码:
import sys
del sys.modules["dummy_module"]
from dummy_module import a
注意:正如“ user2357112支持Monica”所说,这种黑客攻击可能会导致很多问题,我的目的只是进一步解释正在发生的事情,并提供一种快速而肮脏的黑客玩法。