这个包含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
我不明白为什么val
中bar.py
的默认参数不是1
。我很困惑,因为在调用global_val
之前我明确地更新了work()
,但是由于某些原因,旧值仍然用作默认函数参数。
当在global_val
中导入bar.py
时,默认参数似乎已经过预先计算。不是应该在运行时动态编译Python代码吗?
如果有帮助,我正在使用Python 3.6。
答案 0 :(得分:3)
关键是def work(val=global_val[0]):
是在导入时求值的(例如,在from bar import work
中击中main.py
时。)Python函数的默认参数是在该函数求值时求值的is defined并存储在其signature
(here's how you can inspect them)中。
因此,操作顺序为:
main.py
from bar import work
bar
from foo import global_val
foo
def work(val=global_val[0]):
work
的函数并评估其默认参数(global_val[0] == 0
)foo.global_val[0] = 1
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,它将设置正确的值。