首先,做你想做的事是微不足道的。当您 import 一个模块时,该模块对象的单个实例仅由 imports 的任何其他人共享,1 并且该模块对象的属性只是模块的全局变量。所以:
# script.py
import cheese
import eggs
cheese.beans = 10
eggs.dostuff()
# eggs.py
import cheese
print(cheese.beans)
print(cheese.ham)
# cheese.py
ham = 20
如果您运行script.py,它将打印 10,然后是 20。
您当然必须小心顶级模块代码,它按照模块首次导入的顺序运行(这可能很难解决),2 和代码在脚本中(任何人都不应该将其作为模块导入)3,但除此之外,它就可以正常工作,不需要任何特殊的 getter 和 setter 函数。
(如果你出于某种原因需要 getter 和 setter 函数,同样适用于任何对象的 getattr 和 setattr 在模块对象上也能正常工作。)
现在,logging 如何发挥它的魔力?简单的;它只是在其全局变量中存储一个字典。由于模块只有一个实例,因此它的全局变量也只有一个实例,因此 dict 也只有一个实例。
1。如果你想知道 that 是如何在幕后工作的……当你执行import cheese 时,Python 所做的(默认情况下,假设你没有安装任何奇怪的导入钩子)是:首先,是否存在sys.modules['cheese']?如果没有,找到cheese的规范,用它找到一个加载器,用加载器加载代码,exec代码,并将结果存储为sys.modules['cheese']。然后只需return sys.modules['cheese']。这就是为什么每个模块只运行一次顶级代码,不管你import它多少次,这也是为什么imports它的每个人都共享同一个模块对象的副本。
2。你的例子只适用于my_module.my_value = 42 和print(my_module.myvalue)——如果foo 在bar 之前得到imported。但是如果bar首先得到imported,它将得到一个AttributeError,因为显然还没有人设置my_module.my_value。
3。主要原因是当你运行script.py时,它不是作为一个名为script的模块运行的,而是作为一个名为__main__的模块运行的。这就是if __name__ == '__main__': 守卫成语起作用的原因。但是如果其他人做了一个import script,script 不在sys.modules 中,所以 Python 将加载并执行一个单独的 script.py 副本,它有自己单独的全局变量。