代码之家  ›  专栏  ›  技术社区  ›  Cheney

重新分配python模块的变量,但函数将该变量用作默认值不会更改

  •  1
  • Cheney  · 技术社区  · 6 年前

    下面是示例代码:

    # b.py
    c = False
    def d(i=c):
        print(i, c)
    

    我想写 a.py b.d 成为 True, True :

    # a.py
    import b
    b.c = True
    b.d()
    

    但结果是 False, True .

    所以, why how 得到它?


    回答后再写

    为什么:

    # `inspect` may be useful
    import inspect
    v = True
    def f(i=v):
        print(i, v)
    
    s = inspect.signature(f)
    s.parameters
    Out[6]: mappingproxy({'i': <Parameter "i=True">})
    
    2 回复  |  直到 6 年前
        1
  •  5
  •   jedwards    6 年前

    这是不必要的复杂--我们可以把你的问题归结为几行:

    default = "Before"
    
    def foo(bar=default):
        print(bar)
    
    foo()              # "Before"
    default = "After"
    foo()              # "Before"
    

    你期望的行为是 default = "After" 呼唤 foo() 将打印“after”。但它继续印着“以前”。

    python将计算函数的默认参数 一旦 把它锁起来。重新分配的名称 default 稍后对其他内容没有影响(正如我们在上面的片段中看到的)。

    相反,当人们希望列表作为默认参数时,可以使用通常建议的方法:

    default = "Before"
    
    def foo(bar=None):
        if bar is None:
            bar = default
        print(bar)
    
    foo()              # "Before"
    default = "After"
    foo()              # "After"
    

    在本例中,您不是试图更改默认参数,而是更改分配给 bar 当没有指定参数时。每次你打电话 英尺() 没有争论,它将被分配 None 然后函数内部的逻辑将查找并使用全局 违约 .

        2
  •  3
  •   phi    6 年前

    因为默认值是 一旦 在函数创建时。

    def d(i=c):
        print(i, c)
    

    在这里,在 import b 线 d 功能变成

    def d(i=False):
        print(i, c)
    

    所以改变 c 对的默认值没有影响 i 在里面 D .