【问题标题】:Using a variable that is shared across multiple modules as a default function argument使用跨多个模块共享的变量作为默认函数参数
【发布时间】:2019-11-16 07:12:54
【问题描述】:

这个包含 3 个脚本的最小示例最好地说明了手头的问题:

foo.py

global_val = [0]

bar.py

from foo import global_val

def work(val=global_val[0])
    print("global_val: ", global_val[0])
    print("val: ", val)

ma​​in.py

from bar import work
import foo

if __name__ == '__main__':
    foo.global_val[0] = 1
    work()

我期望的输出是:

global_val: 1
val: 1

实际输出:

global_val: 1
val: 0

我不明白为什么bar.pyval 的默认参数不是1。我很困惑,因为我在调用work() 之前明确更新了global_val,但由于某种原因,旧值仍用作默认函数参数。

global_val 被导入bar.py 时,默认参数似乎是预先计算的。 Python代码不应该在运行时动态编译吗?

如果有帮助,我正在使用 Python 3.6。

【问题讨论】:

    标签: python


    【解决方案1】:

    关键是def work(val=global_val[0]): 在导入时被评估(例如当from bar import workmain.py 中被命中。)Python 中函数的默认参数在函数is defined 被评估并存储在它的signature (here's how you can inspect them)。

    因此,操作顺序为:

    1. 运行main.py
    2. from bar import work
    3. 定位并加载bar
    4. from foo import global_val
    5. 定位并加载foo
    6. def work(val=global_val[0]):
    7. 构造一个名为 work 的函数并计算其默认参数 (global_val[0] == 0)
    8. foo.global_val[0] = 1
    9. 调用work

    【讨论】:

      【解决方案2】:

      如果我没记错的话,在你从 bar.py 导入 work func 的那一刻,会执行默认参数,以后更改值也没关系,因为默认参数已经在导入时“声明”了,因为默认参数只计算一次

      【讨论】:

        【解决方案3】:
        item = 0
        
        def bar(val=item):
            print(val)
        
        bar(2)  # 2
        bar()  # 0
        item = 1
        bar()  # 0
        

        这与默认参数有关,而不是全局参数。默认参数被评估一次,而不是每次调用函数时。

        【讨论】:

          【解决方案4】:

          由于默认值在定义/导入时是固定的,您最好设置一个标志或 None 作为默认值,并在函数的头部测试该标志,然后您可以从可用范围(的当然),在执行时作为您想要的实际默认值。

          【讨论】:

            【解决方案5】:

            我想当编译器看到这个时:

            def work(val=global_val[0])
            

            val 的默认值将是当时的 global_val[0]。稍后将其设置为不同的值不会更改函数定义,即,如果未提供该参数的参数,则将 val 变量设置为 0(这是 global_val 的第一个元素)。

            试试这样的:

            def work(val=None):
              if not val:
                global global_val
                val = global_val[0]
            

            在这里,您将 val 设置为已知可以捕获的值,在这种情况下为 None,然后设置适当的值。使用关键字 global 确保您使用全局命名空间中的变量。如果在编译函数定义后稍后更改了 global_val 的值,这将设置正确的值。

            【讨论】:

              猜你喜欢
              • 2016-07-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-11-27
              • 2017-05-23
              • 2020-05-03
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多