Python - 从其他模块中的函数重新分配全局变量的最佳方式

Python - Optimal way to re-assign global variables from function in other module

我有一个名为 entities.py 的模块 - 其中有 2 个 classes 和 2 个全局变量,如下图所示:

FIRST_VAR = ...
SECOND_VAR = ...

class FirstClass:
    [...]

class SecondClass:
    [...]

我还有另一个模块(我们暂时称它为 main.py),我在其中导入 classes 和常量,如下所示:

from entities import FirstClass, SecondClass, FIRST_VAR, SECOND_VAR

在同一个“main.py”模块中,我有另一个常量:THIRD_VAR = ... 和另一个 class,其中使用了所有导入的名称。

现在,我有一个函数,只有在满足特定条件时才会调用它(在我的例子中将配置文件路径作为 CLI 参数传递)。作为我最好的选择,我将其编写如下:

def update_consts_from_config(config: ConfigParser):
    global FIRST_VAR
    global SECOND_VAR
    global THIRD_VAR
    FIRST_VAR = ...
    SECOND_VAR = ...
    THIRD_VAR = ...

虽然 PyCharm 指出了两个问题,但我认为这至少是不准确的。

这工作得很好。

from entities import FirstClass, SecondClass, FIRST_VAR, SECOND_VAR - 这里警告我 FIRST_VAR 和 SECOND_VAR 是未使用的导入,但根据我的理解和测试,它们被使用并且不会在其他地方重新声明,除非函数 update_consts_from_config 被调用。

此外,在 update_consts_from_config 功能下:

global FIRST_VAR - 在这一行和下一行,它说 全局变量 FIRST_VAR 在模块级别未定义

我的问题是,我真的应该关心这些警告吗(因为我认为代码是正确和清晰的),或者我是否遗漏了一些重要的东西并且应该在这里想出一些不同的东西?

我知道我可以做一些事情:

import entities
from entities import FirstClass, SecondClass

FIRST_VAR = entities.FIRST_VAR
SECOND_VAR = entities.SECOND_VAR

并从那里开始工作,但这对我来说似乎有点矫枉过正,entities 模块只有我必须在 main.py 中导入的内容,这也严格依赖于它,因此我宁愿坚持明确导入这些名称而不是仅仅因为这个原因 entities. 引用它们

您认为这里的最佳做法是什么?我希望我的代码清晰、明确并且在某种程度上是最优的。

仅导入实体,然后将其 namespace 中的变量引用到 access/modify 它们。

注意:这种模式,修改其他模块中的常量(然后,对于纯粹主义者来说,与其说是全局常量不如说是常量)是合理的。在很多情况下,我使用常量而不是 magic variables 作为模块级配置。但是,例如为了测试,我可能会进入并修改这些常量。假设将缓存过期时间从 2 天更改为 0.1 秒以测试缓存。或者像你建议的那样,覆盖配置。小心行事,但它可能会有用。

main.py:

import entities

def update_consts_from_config(FIRST_VAR):
    entities.FIRST_VAR = FIRST_VAR

firstclass = entities.FirstClass()

print(f"{entities.FIRST_VAR=} before override")
firstclass.debug()
entities.debug()

update_consts_from_config("override")

print(f"{entities.FIRST_VAR=} after override")
firstclass.debug()
entities.debug()

entities.py:

FIRST_VAR = "ori"

class FirstClass:
    def debug(self):
        print(f"entities.py:{FIRST_VAR=}")


def debug():
    print(f"making sure no closure/locality effects after object instantation {FIRST_VAR=}")

$pythonmain.py


entities.FIRST_VAR='ori' before override
entities.py:FIRST_VAR='ori'
making sure no closure/locality effects after object instantation FIRST_VAR='ori'
entities.FIRST_VAR='override' after override
entities.py:FIRST_VAR='override'
making sure no closure/locality effects after object instantation FIRST_VAR='override'

现在,如果 FIRST_VAR 不是字符串、整数或其他类型的不可变,我认为您应该能够单独导入它并 mutate 它。喜欢 main.py 中的 SECOND_VAR.append("config override")。但是分配到main.py中的全局只会影响影响main.py绑定,所以如果你想分享实际main.py 与实体和其他模块之间的状态,每个人,不仅仅是 main.py 需要 import entities 然后访问 entities.FIRST_VAR.

哦,如果你有:

class SecondClass:

   def __init__(self):
      self.FIRST_VAR = FIRST_VAR

那么它的不可变 string/int 的实例级值将 不会 受到在 一个实例之后完成的任何覆盖的影响创建。像列表或字典这样的可变变量受到影响,因为它们都是指向同一个变量的不同绑定。

最后,关于那些“棘手”的命名空间。 global 在您的原始代码中表示:“不要将 FIRST_VAR 视为要在 update_consts_from_config 的本地名称空间中分配的变量,而是将其分配给 main.py 全局,脚本级命名空间。

不是 的意思是“将它分配给 entities.py 之间神奇共享的某个全局状态main.py”。 __builtins__ 可能 是那个野兽,但修改它在 Python.

中被认为是极其糟糕的形式