在文件之间使用全局变量?

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

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

# ../myproject/main.py


# Define global myList
global myList
myList = []


# Imports
import subfile


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

我试图在subfile.py中使用myList,如下所示

# ../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写入或pickle,这是我不想做的。

396981 次浏览

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

例如:

##test.py:


from pytest import *


print hello_world

和:

##pytest.py


hello_world="hello world!"

你可以把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")

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

# ../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的attr,不是subfile。这将如你所愿。

迈克

问题是你从main.py定义了myList,但是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

通过这种方式,可以实现目标,同时避免多次初始化全局变量。

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

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

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

< p > config.py:

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

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

< p > main.py:

import config
print (config.x)

通常,不要使用Modulename import *。这样做会使导入器的名称空间变得混乱,并使linter更难检测到未定义的名称。

我只是偶然看到这篇文章,并考虑发布我的解决方案,以防任何人遇到和我一样的情况,在开发的程序中有相当多的文件,而你没有时间考虑模块的整个导入序列(如果你从一开始就没有考虑到这一点,比如我)。

在这种情况下,在你初始化全局变量的脚本中,简单地编写一个类,如下所示:

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

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

基于上面的答案和链接,我创建了一个名为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多模块程序中测试,但到目前为止,它工作得很完美。

命名空间噩梦在执行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