直接导入变量产生的值与在 Python 中导入其模块产生的值不同
Importing variable directly yields a different value than importing its module in Python
我有三个模块:
constants
,其中包含加载的配置和其他内容 class
main
,在运行 时初始化constants
user
,导入 constants
并访问其配置。
constants
模块(简化)如下所示:
class Constants:
def __init__(self, filename):
# Read values from INI file
config = self.read_inifile(filename)
self.somevalue = config['ex']['ex']
def read_inifile(self, filename):
# reads inifile
constants: Constants = None
def populate_constants(filename):
global constants
constants = Constants(filename)
一个应该包含配置的简单对象,没有什么开创性的。
函数 populate_constants()
在程序启动时从 main
调用。
现在奇怪的事情发生了 - 当我像这样从 user
导入 constants
模块时,constants
是 None
:
from toplevelpkg.constants import constants
print(constants)
None
但是,如果我这样导入它,constants
会像预期的那样被初始化:
from toplevelpkg import constants
print(constants.constants)
<trumpet.constants.Constants object at 0x035AA130>
这是为什么?
编辑:在我的代码中,尝试读取 constants
的函数是 运行 通过 await loop.run_in_executor(None, method_needing_import)
异步读取的。不确定这是否会导致问题?
(作为一个附带问题,拥有一个解析配置文件并将其作为其成员变量提供的配置保存对象是一种好习惯吗?)
确实有区别
from mymodule import obj
(...)
do_something_with(obj)
和
import mymodule
(...)
do_something_with(mymodule.obj)
在第一种情况下,它充当:
import mymodule
obj = mymodule.obj
del mymodule
这意味着此时,在当前模块中,obj
是一个"global"(在python中实际上意味着'module-level',而不是'application-wide') 名称绑定到任何 mymodule.obj
是 当它被导入时 (在你的例子中: None
)。从那时起,mymodule.obj
和模块本地 obj
名称位于不同的命名空间中(第一个在 mymodule
命名空间中,第二个在当前模块命名空间中),并重新绑定 mymodule.obj
来自任何地方都不会改变当前模块的 obj
所绑定的内容。实际上,就像你这样做一样:
a = 2
b = a
a = 4
在第三条语句之后,b
显然仍然绑定到 2
- 将 a
重新绑定到 4
不会影响 b
。
在第二种情况下 (import mymodule
) 在导入模块的命名空间中绑定的是整个 mymodule
对象,因此如果 mymodule.obj
被反弹(从 mymodule
或其他任何地方)更改将在导入模块中可见。在这种情况下,它等同于
a = {"x": 2}
b = a
a["x"] = 4
在这种情况下,更改也将从 b["x"]
可见,因为 a
和 b
仍然绑定到同一个对象。
wrt/ 你的附带问题:是的,有一些 "config" 对象是很常见的模式。您可能只是想确保您也可以构建它 "from scratch"(我的意思是,不一定来自配置文件)以使单元测试更容易。
我有三个模块:
constants
,其中包含加载的配置和其他内容 classmain
,在运行 时初始化user
,导入constants
并访问其配置。
constants
constants
模块(简化)如下所示:
class Constants:
def __init__(self, filename):
# Read values from INI file
config = self.read_inifile(filename)
self.somevalue = config['ex']['ex']
def read_inifile(self, filename):
# reads inifile
constants: Constants = None
def populate_constants(filename):
global constants
constants = Constants(filename)
一个应该包含配置的简单对象,没有什么开创性的。
函数 populate_constants()
在程序启动时从 main
调用。
现在奇怪的事情发生了 - 当我像这样从 user
导入 constants
模块时,constants
是 None
:
from toplevelpkg.constants import constants
print(constants)
None
但是,如果我这样导入它,constants
会像预期的那样被初始化:
from toplevelpkg import constants
print(constants.constants)
<trumpet.constants.Constants object at 0x035AA130>
这是为什么?
编辑:在我的代码中,尝试读取 constants
的函数是 运行 通过 await loop.run_in_executor(None, method_needing_import)
异步读取的。不确定这是否会导致问题?
(作为一个附带问题,拥有一个解析配置文件并将其作为其成员变量提供的配置保存对象是一种好习惯吗?)
from mymodule import obj
(...)
do_something_with(obj)
和
import mymodule
(...)
do_something_with(mymodule.obj)
在第一种情况下,它充当:
import mymodule
obj = mymodule.obj
del mymodule
这意味着此时,在当前模块中,obj
是一个"global"(在python中实际上意味着'module-level',而不是'application-wide') 名称绑定到任何 mymodule.obj
是 当它被导入时 (在你的例子中: None
)。从那时起,mymodule.obj
和模块本地 obj
名称位于不同的命名空间中(第一个在 mymodule
命名空间中,第二个在当前模块命名空间中),并重新绑定 mymodule.obj
来自任何地方都不会改变当前模块的 obj
所绑定的内容。实际上,就像你这样做一样:
a = 2
b = a
a = 4
在第三条语句之后,b
显然仍然绑定到 2
- 将 a
重新绑定到 4
不会影响 b
。
在第二种情况下 (import mymodule
) 在导入模块的命名空间中绑定的是整个 mymodule
对象,因此如果 mymodule.obj
被反弹(从 mymodule
或其他任何地方)更改将在导入模块中可见。在这种情况下,它等同于
a = {"x": 2}
b = a
a["x"] = 4
在这种情况下,更改也将从 b["x"]
可见,因为 a
和 b
仍然绑定到同一个对象。
wrt/ 你的附带问题:是的,有一些 "config" 对象是很常见的模式。您可能只是想确保您也可以构建它 "from scratch"(我的意思是,不一定来自配置文件)以使单元测试更容易。