289

我对全局变量的工作方式有点困惑。我有一个大项目,大约有 50 个文件,我需要为所有这些文件定义全局变量。

我所做的是在我的项目main.py文件中定义它们,如下所示:

# ../myproject/main.py

# Define global myList
global myList
myList = []

# Imports
import subfile

# Do something
subfile.stuff()
print(myList[0])

我正在尝试使用myListin subfile.py,如下所示

# ../myproject/subfile.py

# Save "hey" into myList
def stuff():
    globals()["myList"].append("hey")

我尝试了另一种方法,但也没有用

# ../myproject/main.py

# Import globfile    
import globfile

# Save myList into globfile
globfile.myList = []

# Import subfile
import subfile

# Do something
subfile.stuff()
print(globfile.myList[0])

在里面subfile.py我有这个:

# ../myproject/subfile.py

# Import globfile
import globfile

# Save "hey" into myList
def stuff():
    globfile.myList.append("hey")

但同样,它没有用。我应该如何实现这个?我知道它不能那样工作,当这两个文件并不真正了解对方(以及子文件不知道主文件),但我想不出如何做到这一点,而不使用 io 写入或泡菜,哪个我不想做。

4

9 回答 9

420

问题是您从 定义myListmain.py,但subfile.py需要使用它。这是解决此问题的一种简洁方法:将所有全局变量移动到一个文件中,我称之为这个文件settings.py。该文件负责定义全局变量并初始化它们:

# settings.py

def init():
    global myList
    myList = []

接下来,您subfile可以导入全局变量:

# subfile.py

import settings

def stuff():
    settings.myList.append('hey')

请注意,subfile不调用init()- 该任务属于main.py

# main.py

import settings
import subfile

settings.init()          # Call only once
subfile.stuff()         # Do stuff with global var
print settings.myList[0] # Check the result

这样,您就可以实现目标,同时避免多次初始化全局变量。

于 2012-10-23T16:16:48.337 回答
157

请参阅 Python 的关于跨模块共享全局变量的文档:

在单个程序中跨模块共享信息的规范方法是创建一个特殊模块(通常称为 config 或 cfg)。

配置文件:

x = 0   # Default value of the 'x' configuration setting

在应用程序的所有模块中导入配置模块;然后该模块可作为全局名称使用。

主要.py:

import config
print (config.x)

一般来说,不要使用from modulename import *。这样做会使导入器的命名空间变得混乱,并使 linter 更难检测未定义的名称。

于 2017-08-12T04:24:47.673 回答
23

您可以将 Python 全局变量视为“模块”变量——因此它们比 C 中的传统“全局变量”有用得多。

全局变量实际上是在模块中定义的__dict__,并且可以作为模块属性从该模块外部访问。

因此,在您的示例中:

# ../myproject/main.py

# Define global myList
# global myList  - there is no "global" declaration at module level. Just inside
# function and methods
myList = []

# Imports
import subfile

# Do something
subfile.stuff()
print(myList[0])

和:

# ../myproject/subfile.py

# Save "hey" into myList
def stuff():
     # You have to make the module main available for the 
     # code here.
     # Placing the import inside the function body will
     # usually avoid import cycles - 
     # unless you happen to call this function from 
     # either main or subfile's body (i.e. not from inside a function or method)
     import main
     main.mylist.append("hey")
于 2012-10-23T16:04:31.520 回答
12

使用from your_file import *应该可以解决您的问题。它定义了所有内容,以便全局可用(当然,导入中的局部变量除外)。

例如:

##test.py:

from pytest import *

print hello_world

和:

##pytest.py

hello_world="hello world!"
于 2012-10-23T15:59:49.400 回答
10

Hai Vu 的回答效果很好,只有一条评论:

如果您在其他模块中使用了全局并且您想动态设置全局,请注意在设置全局变量后导入其他模块,例如:

# settings.py
def init(arg):
    global myList
    myList = []
    mylist.append(arg)


# subfile.py
import settings

def print():
    settings.myList[0]


# main.py
import settings
settings.init("1st")     # global init before used in other imported modules
                         # Or else they will be undefined

import subfile    
subfile.print()          # global usage
于 2015-12-23T09:23:58.137 回答
4

您的第二次尝试将完美运行,并且实际上是处理您希望全局可用的变量名称的一种非常好的方法。但是你在最后一行有一个名称错误。应该是这样的:

# ../myproject/main.py

# Import globfile    
import globfile

# Save myList into globfile
globfile.myList = []

# Import subfile
import subfile

# Do something
subfile.stuff()
print(globfile.myList[0])

看到最后一行了吗?myList 是 globfile 的属性,而不是子文件。这将按您的意愿工作。

麦克风

于 2012-10-23T16:08:42.443 回答
2

基于上面的答案和链接,我创建了一个名为的新模块global_variables.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# ==============================================================================
#
#       global_variables.py - Global variables shared by all modules.
#
# ==============================================================================

USER = None                 # User ID, Name, GUID varies by platform

def init():
    """ This should only be called once by the main module
        Child modules will inherit values. For example if they contain
        
            import global_variables as g
            
        Later on they can reference 'g.USER' to get the user ID.
    """
    global USER

    import getpass
    USER = getpass.getuser()

# End of global_variables.py

然后在我的主模块中我使用这个:

import global_variables as g
g.init()

在另一个子导入模块中,我可以使用:

import global_variables as g
# hundreds of lines later....
print(g.USER)

我只花了几分钟在两个不同的 python 多模块程序中进行了测试,但到目前为止它运行良好。

于 2021-07-07T00:05:03.087 回答
1

刚看到这个帖子,想发一下我的解决方案,以防万一有人和我有同样的情况,开发的程序中有很多文件,你没有时间考虑整个模块的导入顺序(如果您从一开始就没有正确地考虑到这一点,例如我所做的)。

在这种情况下,在您启动全局的脚本中,只需编写一个如下所示的类:

class My_Globals:
  def __init__(self):
    self.global1 = "initial_value_1"
    self.global2 = "initial_value_2"
    ...

然后使用,而不是脚本中您启动全局变量的行,而不是

global1 = "initial_value_1"

采用

globals = My_Globals()

然后我能够通过以下方式检索/更改任何这些全局变量的值

globals.desired_global

在任何脚本中,这些更改也会自动应用于使用它们的所有其他脚本。由于本文/讨论here中提到的问题,所有现在都可以使用以前失败的完全相同的导入语句。与简单的全局变量导入相比,我只是认为全局对象的属性动态变化而无需考虑/更改任何导入逻辑,这绝对是解决此类问题的最快和最简单(供以后访问)的方法为了我。

于 2020-10-28T18:04:31.500 回答
0

当你这样做时,命名空间噩梦就会出现from config import mySharedThing。怎么强调都不过分。

from在其他地方没问题。

您甚至可以拥有一个完全为空的配置模块。

# my_config.py
pass
# my_other_module.py
import my_config

def doSomething():
    print(my_config.mySharedThing.message)
# main.py
from dataclasses import dataclass
from my_other_module import doSomething
import my_config

@dataclass
class Thing:
    message: str

my_config.mySharedThing = Thing('Hey everybody!')
doSomething()

结果:

$ python3 main.py
Hey everybody!

但是使用你拉进来的物体会让from你感到沮丧。

# my_other_module.py
from my_config import mySharedThing

def doSomething():
    print(mySharedThing.message)

结果:

$ python3 main.py
ImportError: cannot import name 'mySharedThing' from 'my_config' (my_config.py)

也许你会尝试像这样修复它:

# my_config.py
mySharedThing = None

结果:

$ python3 main.py
AttributeError: 'NoneType' object has no attribute 'message'

然后也许你会找到这个页面并尝试通过添加一个 init() 方法来解决它。

但整个问题是from.

于 2021-09-12T20:38:37.553 回答