我已经使用Python多年了,为分发创建新的模块仍然令人困惑和难以理解;这真的很令人沮丧。 我需要一位专家来解释这一点。
我最近发现,在子模块中设置全局变量的行为会有所不同,具体取决于模块在__init__.py
文件中的导入方式。
我有这样的设置:
prime.py
import sub
sub.somevar = False
sub.show()
sub.py
somevar = True
def show():
global somevar
print("somevar is {}".format(somevar))
此代码生成预期的输出:
somevar is False.
当 main.py 和 sub.py 位于同一目录中时。 当我使用setuptools将sub
作为单独的可安装模块时,它停止工作。
我的sub
可安装模块目录结构如下所示:
# ls
setup.py sub README.md
# ls sub
__init__.py sub.py
其中__init__.py
包含文本:
from .sub import *
此设置似乎非常适合安装和分发模块,适用于 Python2 和 Python3。
问题是现在当我用prime.py
导入全局变量设置时,全局变量设置被破坏了;任何从prime.py
设置somevar
的尝试都不会像预期的那样改变sub.py
函数的变量。 我得到输出:
somevar is True
这到底是怎么回事? 为什么 python 模块导入如此挑剔?
它与您的项目结构无关,而与您导入项目结构的方式无关。
我认为这很容易理解。由于somevar
是一种值类型,当您使用隐式from x import somevar
from x import *
时,您会在当前命名空间中获得somevar
的副本。
而且因为它只是一个副本,所以更改它不会更改子模块中的somevar
。
但如果somevar
是一个列表,例如:
# In sub.py
somevar = [True]
你把它改成
# In prime.py
somevar[0] = False
然后它就会起作用。
为了快速修复,您可以简单地使用"setter"getter"行为:
prime.py
import sub
sub.set_somevar(False)
myFalseVar = sub.get_somevar()
sub.py
somevar = True
def get_somevar():
global somevar
return somevar
def set_somevar(var):
global somevar
somevar = var