<p>每个模块都有自己的全局变量。Python的行为完全符合预期。更新<code>globalEx1</code>的<code>a</code>指向其他对象不会影响<code>globalEx2</code>的<code>a</code>指向的位置。你知道吗</p>
<p>有各种各样的方法来解决这个问题,具体取决于你想要什么。你知道吗</p>
<ol>
<li>在<code>setvalue()</code>调用之后重新导入<code>a</code></li>
<li><code>return a</code>并赋值,如<code>a = setvalue()</code>。你知道吗</li>
<li><code>import globalEx1</code>并使用<code>globalEx1.a</code>而不是<code>a</code>。(或使用<code>import globalEx1 as</code>和较短的名称。)</li>
<li>将<code>globalEx2</code>的<code>globals()</code>作为参数传递给<code>setvalue</code>,并设置该参数的值。你知道吗</li>
<li>使<code>a</code>成为一个包含</em>您的值的可变对象,如list、dict或<code>types.SimpleNamespace</code>,并在<code>setvalue</code>中对其进行变异。你知道吗</li>
<li>在<code>setvalue</code>内使用<code>inspect</code>从调用方的堆栈帧获取调用方的全局变量。(方便,但易碎。)
<hr/></li>
</ol>
<blockquote>
<p>Last option looks suitable for me.. it will do the job with minimal code change but can I update globals of multiple modules using same way? or it only gives me the caller's globals? </p>
</blockquote>
<p>选项6实际上是最危险的。调用者本身基本上成为函数的一个隐藏参数,因此来自另一个模块的装饰器之类的东西可以在没有警告的情况下破坏它。选项4只是将隐藏参数显式化,所以它不那么脆弱。你知道吗</p>
<p>如果您需要在两个以上的模块上使用它,那么选项6就不够好,因为它只提供当前的调用堆栈。选项3可能是最可靠的你似乎要做的事。你知道吗</p>
<hr/>
<blockquote>
<p>How does option 1 work? I mean is it about running again -> "from globalEx1 import *" because I have many variables like 'a'.</p>
</blockquote>
<p>模块在第一次导入时成为对象,并且保存在<code>sys.modules</code>缓存中,因此再次导入不会再次执行模块。<code>from ... import</code>(即使使用了<code>*</code>)也只是从模块对象获取属性,并将它们添加到本地范围(如果在顶层完成,那么就是模块全局变量,也就是在任何定义之外)</p>
<p>模块对象的<code>__dict__</code>基本上是它的全局变量,因此任何改变模块全局变量的函数都会影响结果模块对象的属性,即使它是在导入模块之后完成的。你知道吗</p>
<blockquote>
<p>We cannot do from 'globalEx1 import *' from a python function, any alternative to this?</p>
</blockquote>
<p>star语法只允许在顶层使用。但请记住,它只是从模块对象读取属性。所以你可以得到所有模块属性的dict,比如</p>
<pre><code>return vars(globalEx1)
</code></pre>
<p>这会给你比<code>*</code>更多的东西。默认情况下,它不返回以<code>_</code>开头的名称,否则不返回在<code>__all__</code>中指定的子集。您可以使用dict comprehension过滤结果dict,甚至<code>.update()</code>使用结果过滤其他模块的全局dict。你知道吗</p>
<p>但是,与其重新实现这个过滤逻辑,不如使用exec使其成为顶层。那么你得到的唯一奇怪的钥匙就是<code>__builtins__</code></p>
<pre><code>namespace = {}
exec('from globalEx1 import *', namespace)
del namespace['__builtins__']
return namespace
</code></pre>
<p>然后你就可以<code>globals().update(namespace)</code>或者别的什么了。你知道吗</p>
<p>像这样使用<code>exec</code>可能被认为是不好的形式,但老实说,<code>import *</code>也是如此。你知道吗</p>