使用在多个模块之间共享的变量作为默认函数参数

时间:2019-07-05 16:40:29

标签: python

这个包含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)

main.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

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

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

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

5 个答案:

答案 0 :(得分:3)

关键是def work(val=global_val[0]):是在导入时求值的(例如,在from bar import work中击中main.py时。)Python函数的默认参数是在该函数求值时求值的is defined并存储在其signaturehere'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

答案 1 :(得分:1)

如果我没记错,那是在从bar.py导入work func的那一刻,执行了默认参数,以后再更改该值都不重要,因为默认参数已在导入中“声明”,因为默认参数仅被评估一次

答案 2 :(得分:0)

item = 0

def bar(val=item):
    print(val)

bar(2)  # 2
bar()  # 0
item = 1
bar()  # 0

这与默认参数而不是全局变量有关。默认参数是一次求值,而不是每次调用函数时都要求值。

答案 3 :(得分:0)

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

答案 4 :(得分:0)

我认为当编译器看到此内容时:

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,它将设置正确的值。