【问题标题】:Global variable with imports带导入的全局变量
【发布时间】:2011-06-10 01:31:31
【问题描述】:

first.py

​​>
myGlobal = "hello"

def changeGlobal():
   myGlobal="bye"

second.py

​​>
from first import *

changeGlobal()
print myGlobal

我得到的输出是

你好

虽然我认为应该是

再见

为什么调用changeGlobal()函数后全局变量myGlobal没有变化?

【问题讨论】:

    标签: python global


    【解决方案1】:

    试试:

    def changeGlobal():
        global myGlobal
        myGlobal = "bye"
    

    实际上,这也行不通。当您import * 时,您创建了一个新的 local 模块全局 myGlobal,它不受您想要的更改的影响(只要您不改变变量,请参见下文)。你可以改用这个:

    import nice
    
    nice.changeGlobal()
    print nice.myGlobal
    

    或者:

    myGlobal = "hello"
    
    def changeGlobal():
       global myGlobal
       myGlobal="bye"
    
    changeGlobal()
    

    但是,如果您的 global 是一个可变容器,那么您现在持有对可变容器的引用并且能够看到对其所做的更改:

    myGlobal = ["hello"]
    
    def changeGlobal():
        myGlobal[0] = "bye"
    

    【讨论】:

    • 我忘了在我的原始帖子中提到我用 global 尝试过它,但它没有用。我不知道用 * 导入时我创建了一个新的本地变量。谢谢!
    • 说你创建一个新的本地是不太正确的。您实际上是在第二个模块中创建一个新的全局变量。每个模块都有自己的一组全局变量。
    • import nice 是那里的最佳选择,但是我如何导入具有绝对路径的文件夹作为包,如 import app.base.admin.crud as cx stackoverflow.com/questions/48098231/…
    【解决方案2】:

    我曾经和你有同样的担忧,阅读 Norman MatloffQuick and Painless Python Tutorial 的以下部分确实是一个很好的帮助。以下是您需要了解的内容(抄自 Matloff 的书):

    Python 并不像 C/C++ 那样真正允许全局变量。导入的 Python 模块将无法直接访问导入它的模块中的全局变量,反之亦然。

    例如,考虑这两个文件,x.py

    # x.py
    import y
    def f():
      global x
      x = 6
    def main():
      global x
      x = 3
    f()
    y.g()
    if __name__ == ’__main__’:
      main()
    

    y.py

    # y.py
    def g():
      global x
      x += 1
    

    x.py 中的变量 x 在整个模块 x.py 中可见,但在 y.py 中不可见。实际上,执行该行 x += 1

    在后者中会导致出现错误信息,“global name 'x' is not defined。”

    确实,模块中的全局变量只是该模块的属性(即成员实体),类似于类变量在类中的作用。当模块 B 被模块 A 导入时,B 的命名空间被复制到 A 的。如果模块 B 有一个全局变量 X,那么模块 A 将创建一个具有该名称的变量,其初始值是模块 B 所具有的任何值它在导入时具有该名称的变量。但其中一个模块中对 X 的更改不会反映在另一个模块中。

    假设B中的X确实发生了变化,但我们希望A中的代码能够获得B中X的最新值。我们可以通过在 B 中包含一个名为 GetX() 的函数来做到这一点。假设 AB 导入所有内容,那么 A 将获得一个函数 GetX(),它是B 的该名称的函数,其唯一目的是返回 X 的值。除非 B 更改该函数(这是可能的,例如可以分配函数) ,两个模块中的函数总是相同的,因此A可以使用它的函数来获取B中X的值。

    【讨论】:

    • 谢谢,python 全局变量不是全局变量,它们是模块属性——许多人成为这个“错误”的牺牲品。现在,如果你:'from foo import *' 是否有一个'foo' 模块可能有来自 foo 的'globals'?还是 foo 中的所有内容现在都合并到“当前模块”中?
    • 我的测试与您的陈述相矛盾,即“导入模块 B 时”......当我从命令行调用 python 时(即不在模块 A 中)并导入模块,导入模块的“全局变量”不会出现(要复制)到当前命名空间中。导入模块的名称在命名空间(globals())中,其中定义了moduleName.itsGlobalVar,但它的GlobalVar不在globals()中
    【解决方案3】:

    Python 全局变量不是全局变量

    正如 wassimans 上面指出的,它们本质上是定义它们的模块(或包含定义它们的函数的模块)范围内的属性。

    人们遇到的第一个困惑(错误)是没有意识到函数具有本地名称空间,并且在函数中设置变量使其成为函数的本地变量,即使他们打算让它更改(全局)变量在封闭模块中具有相同名称。 (宣布名称 在函数中的“全局”语句中,或在设置之前访问(全局)变量。)

    人们遇到的第二个混淆(错误)是每个模块(即导入的文件)都包含自己的所谓“全局”名称空间。我猜 python things the world(globe) 是模块——也许我们正在寻找跨越多个地球的“通用”变量。

    第三个困惑(我现在开始理解)是__main__ 模块中的“全局变量”在哪里?即,如果您在交互模式下从命令行启动 python,或者如果您调用 python 脚本(从命令 shell 中键入 foo.py 的名称) - 没有导入您可以使用其名称的模块。

    'globals()' 或 globals().keys() 的内容——给你一个全局列表——似乎可以通过以下方式访问:dir(sys.modules['__main__']) 似乎已加载的 python 脚本(或没有加载脚本的交互式会话)的模块,名为:__name__ 的模块没有全局名称,但可以作为名称为“__main__”的模块访问系统所有活动模块的列表,sys.modules

    【讨论】:

    • @Andrew 什么没用?当你做你所做的事情时它做了什么?
    • sys.modules['main']
    • 哦!文本格式化程序将双下划线解释为“使这个斜体”。我“转义”了 namemain 周围的双下划线,以便它们正确显示。此外,它似乎需要 dir() 而不是 .keys()
    • 太棒了,它现在可以工作了,这太完美了,谢谢!只需将例如:g = sys.modules['__main__'] 放在导入文件的顶部,然后他们就可以访问g.whatever
    猜你喜欢
    • 2018-07-23
    • 1970-01-01
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-06
    • 2017-03-01
    相关资源
    最近更新 更多