【问题标题】:Python globals and keyword argumentsPython 全局变量和关键字参数
【发布时间】:2021-01-22 00:27:32
【问题描述】:

为什么下面的test2() 会打印“True False”?我会期待“假假”。

我希望test2() 将全局值EC 更改为False,因此ec 也应该为False。

为什么不呢?

有没有一种直接的方法来获得“False False”行为?

EC = True

def test1(ec=EC):
    print(ec, EC)

def test2():

    global EC
    EC=False

    test1()

【问题讨论】:

  • @AryaMcCarthy:这是由相同的底层行为引起的(默认在函数定义时绑定),但它的表现大致相反(预期的变化不会发生,这个问题是关于发生意外的变化)。这是一个有用的参考,但它不是重复的。

标签: python global keyword


【解决方案1】:

函数默认绑定在函数定义,而不是函数调用。对于像bool 这样的不可变类型,在定义test1 之后对EC 所做的任何操作都不会影响绑定到test1ec 参数的默认值。

如果你想要调用时间绑定,你会被困在接受一个哨兵默认值,并动态加载以响应获取它,例如:

def test1(ec=None):
    if ec is None:
        ec = EC
    ...

如果None 可能是一个有效的参数(因此不能用作哨兵值),您可以制作和使用自己的哨兵对象,而不是用于其他目的:

_test1_sentinel = object()  # Cheapest way to make new, guaranteed unique object
def test1(ec=_test1_sentinel):
    if ec is _test1_sentinel:
        ec = EC
    ...

【讨论】:

    【解决方案2】:

    首先,这是一个默认值,而不是关键字参数。如果你想传递关键字参数,看起来像这样:

    def test1(ec):
        print(ec)
    
    test1(ec=True)
    

    其次,与大多数具有默认参数值的语言不同,Python 在函数定义时评估默认值,而不是函数调用时。这是一个非常不寻常的设计决策,会导致很多问题。典型的解决方法是使用像 None 这样的标记值作为默认值,如果检测到标记,则计算函数内部的“真实”默认值:

    EC = True
    
    def test1(ec=None):
        if ec is None:
            ec = EC
        print(ec, EC)
    
    def test2():
    
        global EC
        EC=False
    
        test1()
    

    【讨论】:

      【解决方案3】:

      为什么会这样?

      我认为你的问题是这样的:

      • 当您创建变量 EC 时,它会保留在您记忆中的位置 A。
      • 当您创建函数 test1() 时,它会保留在位置 B。
      • 当您创建函数 test2() 时,它会保留在位置 C。

      假设:在test2() 中,您将EC 设置为全局变量,它会运行,但是将global EC 保存在位置D 中,在test2() 的末尾,EC 从D 中获取它的值。

      这意味着当您在 test2() 中调用 test1() 时,设置为 ec 的 EC 将保留在 A 中,而不是 D 中。但不知何故,当您打印时,它会在您的内存中查找 D。

      我的解决方案

      EC = True
      
      def test1(ec=EC):
          print(ec, EC)
      
      def test2():
          global EC
          EC = False
          test1(ec=EC)
      

      这是我的代码,它适用于 Python 3.6.9

      我的证明

      为了理解这一点,在 Python 中有两个内置函数是 hex()id(),所以当你想找到变量在内存中的位置时,可以通过 hex(id(EC)) 进行检查

      您可以将代码运行为:

      EC = True
      print(hex(id(EC)))
      def test1(ec=EC):
          print(ec, EC)
      print(hex(id(test1)))
      def test2():
          global EC
          EC = False
          print(hex(id(EC)))
          test1()
      print(hex(id(test2)))
      

      您会发现您的 global EC 和第一个 EC 变量位于 2 个不同的位置。这就是为什么你会得到True False的结果

      【讨论】:

        猜你喜欢
        • 2012-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-26
        相关资源
        最近更新 更多