如何创建跨模块变量?

2025-01-15 08:45:00
admin
原创
98
摘要:问题描述:该__debug__变量非常方便,因为它会影响每个模块。如果我想创建另一个以相同方式工作的变量,我该怎么做?该变量(我们不妨将其称为“foo”)不必是真正的全局变量,也就是说,如果我在一个模块中更改 foo,则其他模块中的变量也会更新。如果我可以在导入其他模块之前设置 foo,然后它们将看到相同的值...

问题描述:

__debug__变量非常方便,因为它会影响每个模块。如果我想创建另一个以相同方式工作的变量,我该怎么做?

该变量(我们不妨将其称为“foo”)不必是真正的全局变量,也就是说,如果我在一个模块中更改 foo,则其他模块中的变量也会更新。如果我可以在导入其他模块之前设置 foo,然后它们将看到相同的值,那就没问题了。


解决方案 1:

如果您需要一个全局跨模块变量,也许只需简单的全局模块级变量就足够了。

a.py:

var = 1

py:

import a
print a.var
import c
print a.var

复制代码

import a
a.var = 2

测试:

$ python b.py
# -> 1 2

真实世界的例子:Django 的 global_settings.py(尽管在 Django 应用程序中设置是通过导入对象 django.conf.settings来使用的)。

解决方案 2:

我绝不认可这种解决方案。但是如果你向__builtin__模块添加一个变量,它将像全局变量一样可以从任何其他包含的模块访问__builtin__——默认情况下,所有模块都可以访问它。

a.py 包含

print foo

b.py 包含

import __builtin__
__builtin__.foo = 1
import a

结果是打印了“1”。

编辑:模块__builtin__可用作本地符号__builtins__——这就是这两个答案之间存在差异的原因。另请注意,在 python3 中__builtin__已重命名为builtins

解决方案 3:

我认为在很多情况下这样做是有意义的,而且可以让一些全局变量在多个(紧密耦合的)模块中为人所知,这样可以简化编程。本着这种精神,我想详细阐述一下这样一种想法:让一个全局变量模块被那些需要引用它们的模块导入。

当只有一个这样的模块时,我将其命名为“g”。在其中,我为每个打算视为全局的变量分配默认值。在每个使用其中任何一个的模块中,我不会使用“from g import var”,因为这只会导致一个局部变量,该变量仅在导入时从 g 初始化。我以 g.var 的形式进行大多数引用,“g.”不断提醒我,我正在处理的变量可能被其他模块访问。

如果模块中某个函数经常使用这种全局变量的值,那么该函数可以进行本地复制:var = g.var。但是,重要的是要意识到对 var 的赋值是本地的,并且如果不在赋值中明确引用 g.var,则无法更新全局 g.var。

请注意,您还可以让多个这样的全局模块由模块的不同子集共享,以使事情控制得更严格一些。我使用全局模块的短名称的原因是为了避免代码因它们的出现而变得过于混乱。只要有一点经验,它们就只需要 1 或 2 个字符就足够容易记忆了。

当 x 尚未在 g 中定义时,仍然可以对 gx 进行赋值,然后另一个模块可以访问 gx。但是,即使解释器允许这样做,这种方法也不是那么透明,我确实避免这样做。仍然有可能由于赋值的变量名称拼写错误而意外在 g 中创建一个新变量。有时检查 dir(g) 有助于发现可能因此类意外而产生的任何意外名称。

解决方案 4:

定义一个模块(称之为“globalbaz”)并在其中定义变量。所有使用此“伪全局”的模块都应导入“globalbaz”模块,并使用“globalbaz.var_name”引用它

无论更改的位置在哪里,这都可以正常工作,您可以在导入之前或之后更改变量。导入的模块将使用最新值。(我在一个玩具示例中测试了这一点)

为了澄清起见,globalbaz.py 看起来就像这样:

var_name = "my_useful_string"

解决方案 5:

您可以将一个模块的全局变量传递给另一个模块:

在模块 A 中:

import module_b
my_var=2
module_b.do_something_with_my_globals(globals())
print my_var

在模块 B 中:

def do_something_with_my_globals(glob): # glob is simply a dict.
    glob["my_var"]=3

解决方案 6:

全局变量通常不是一个好主意,但你可以通过分配给来实现__builtins__

__builtins__.foo = 'something'
print foo

此外,模块本身也是可以从任何模块访问的变量。因此,如果您定义一个名为的模块my_globals.py

# my_globals.py
foo = 'something'

然后你也可以在任何地方使用它:

import my_globals
print my_globals.foo

使用模块而不是修改__builtins__通常是执行此类全局变量的更简洁的方法。

解决方案 7:

您已经可以使用模块级变量来实现这一点。无论从哪个模块导入,模块都是相同的。因此,您可以将变量设置为模块级变量,无论将其放入哪个模块,都可以从其他模块访问它或为其赋值。最好调用一个函数来设置变量的值,或者使其成为某个单例对象的属性。这样,如果您最终需要在变量更改时运行某些代码,则可以这样做而不会破坏模块的外部接口。

这通常不是一种很好的做事方式 — — 使用全局变量也很少 — — 但我认为这是最干净的方式。

解决方案 8:

我想发表一个答案,说存在找不到变量的情况。

循环导入可能会破坏模块行为。

例如:

首先

import second
var = 1

第二.py

import first
print(first.var)  # will throw an error because the order of execution happens before var gets declared.

主程序

import first

在这个例子中,这应该是显而易见的,但在大型代码库中,这可能确实令人困惑。

解决方案 9:

我想知道,通过使用类命名空间而不是全局/模块命名空间来传递变量值,是否可以避免使用全局变量的一些缺点(例如,请参阅http://wiki.c2.com/?GlobalVariablesAreBad)。以下代码表明这两种方法本质上是相同的。使用类命名空间有一点优势,如下所述。

以下代码片段还表明可以在全局/模块命名空间和类命名空间中动态创建和删除属性或变量。

墙.py

# Note no definition of global variables

class router:
    """ Empty class """

我称这个模块为“墙”,因为它用于传递变量。它将充当临时定义空类“路由器”的全局变量和类范围属性的空间。

源码.py

import wall
def sourcefn():
    msg = 'Hello world!'
    wall.msg = msg
    wall.router.msg = msg

此模块导入 wall 并定义一个函数,sourcefn该函数定义一条消息并通过两种不同的机制发出该消息,一种是通过全局变量,一种是通过路由器函数。请注意,变量wall.msgwall.router.message在此处首次在其各自的命名空间中定义。

目标文件

import wall
def destfn():

    if hasattr(wall, 'msg'):
        print 'global: ' + wall.msg
        del wall.msg
    else:
        print 'global: ' + 'no message'

    if hasattr(wall.router, 'msg'):
        print 'router: ' + wall.router.msg
        del wall.router.msg
    else:
        print 'router: ' + 'no message'

此模块定义了一个函数destfn,该函数使用两种不同的机制来接收源发出的消息。它允许变量“msg”可能不存在。destfn此外,一旦显示变量,它还会删除这些变量。

主程序

import source, dest

source.sourcefn()

dest.destfn() # variables deleted after this call
dest.destfn()

此模块按顺序调用先前定义的函数。第一次调用后,dest.destfn变量wall.msgwall.router.msg不再存在。

该程序的输出是:

全局:你好,世界!

路由器:你好,世界!

全局:无消息

路由器:无消息

上述代码片段表明模块/全局和类/类变量机制本质上是相同的。

如果要共享大量变量,则可以通过使用多个 wall 类型的模块(例如 wall1、wall2 等)或在一个文件中定义多个 router 类型的类来管理命名空间污染。后者稍微整洁一些,因此可能代表了使用类变量机制的边际优势。

解决方案 10:

这听起来像是修改__builtin__名称空间。具体做法如下:

import __builtin__
__builtin__.foo = 'some-value'

不要__builtins__直接使用(注意多余的“s”)——显然这可以是字典或模块。感谢 ΤΖΩΤΖΙΟΥ 指出这一点,更多信息可在此处找到。

现在foo可在任何地方使用。

我一般不建议这样做,但是否使用取决于程序员。

对其分配必须按照上述方式进行,仅设置foo = 'some-other-value'只会将其设置在当前命名空间中。

解决方案 11:

我将其用于一些我认为确实缺失的内置原始函数。其中一个例子是 find 函数,它具有与 filter、map、reduce 相同的使用语义。

def builtin_find(f, x, d=None):
    for i in x:
        if f(i):
            return i
    return d

import __builtin__
__builtin__.find = builtin_find

一旦运行(例如,通过在入口点附近导入),所有模块都可以使用 find(),就像它是内置的一样。

find(lambda i: i < 0, [1, 3, 0, -5, -10])  # Yields -5, the first negative.

注意:当然,您可以使用过滤器和另一行来测试零长度,或者使用一种奇怪的行来减少长度,但我总是觉得这很奇怪。

解决方案 12:

我可以使用字典实现跨模块可修改(或可变)变量:

# in myapp.__init__
Timeouts = {} # cross-modules global mutable variables for testing purpose
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 60

# in myapp.mod1
from myapp import Timeouts

def wait_app_up(project_name, port):
    # wait for app until Timeouts['WAIT_APP_UP_IN_SECONDS']
    # ...

# in myapp.test.test_mod1
from myapp import Timeouts

def test_wait_app_up_fail(self):
    timeout_bak = Timeouts['WAIT_APP_UP_IN_SECONDS']
    Timeouts['WAIT_APP_UP_IN_SECONDS'] = 3
    with self.assertRaises(hlp.TimeoutException) as cm:
        wait_app_up(PROJECT_NAME, PROJECT_PORT)
    self.assertEqual("Timeout while waiting for App to start", str(cm.exception))
    Timeouts['WAIT_JENKINS_UP_TIMEOUT_IN_SECONDS'] = timeout_bak

启动时test_wait_app_up_fail,实际超时时间为3秒。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1579  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1355  
  信创产品在政府采购中的占比分析随着信息技术的飞速发展以及国家对信息安全重视程度的不断提高,信创产业应运而生并迅速崛起。信创,即信息技术应用创新,旨在实现信息技术领域的自主可控,减少对国外技术的依赖,保障国家信息安全。政府采购作为推动信创产业发展的重要力量,其对信创产品的采购占比情况备受关注。这不仅关系到信创产业的发展前...
信创和国产化的区别   8  
  信创,即信息技术应用创新产业,旨在实现信息技术领域的自主可控,摆脱对国外技术的依赖。近年来,国货国用信创发展势头迅猛,在诸多领域取得了显著成果。这一发展趋势对科技创新产生了深远的推动作用,不仅提升了我国在信息技术领域的自主创新能力,还为经济社会的数字化转型提供了坚实支撑。信创推动核心技术突破信创产业的发展促使企业和科研...
信创工作   9  
  信创技术,即信息技术应用创新产业,旨在实现信息技术领域的自主可控与安全可靠。近年来,信创技术发展迅猛,对中小企业产生了深远的影响,带来了诸多不可忽视的价值。在数字化转型的浪潮中,中小企业面临着激烈的市场竞争和复杂多变的环境,信创技术的出现为它们提供了新的发展机遇和支撑。信创技术对中小企业的影响技术架构变革信创技术促使中...
信创国产化   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用