Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 变异、重新绑定、复制值和赋值运算符之间的差异_Python_Arguments_Default Value - Fatal编程技术网

Python 变异、重新绑定、复制值和赋值运算符之间的差异

Python 变异、重新绑定、复制值和赋值运算符之间的差异,python,arguments,default-value,Python,Arguments,Default Value,在f1中,参数l有一个默认值赋值,并且只计算一次,因此三个打印输出1、2和3。为什么f2不做类似的事情 结论: 为了使我所学到的内容更容易为本帖的未来读者导航,我总结如下: 我找到了关于这个主题的很好的教程 我做了一些简单的比较,变异,重新绑定,复制值,和赋值运算符之间的差异 因为在f2中,名称b是回弹的,而在f1中,对象l是变异的 在f1中,您将值存储在一个数组中,或者更好的是,在Python中存储一个列表,在f2中,您将对传递的值进行操作。这就是我对它的解释。我可能错了这在一篇文章中有详细

f1
中,参数
l
有一个默认值赋值,并且只计算一次,因此三个
打印
输出1、2和3。为什么
f2
不做类似的事情

结论: 为了使我所学到的内容更容易为本帖的未来读者导航,我总结如下:

  • 我找到了关于这个主题的很好的教程

  • 我做了一些简单的比较,变异重新绑定复制值,和赋值运算符之间的差异


    • 因为在
      f2
      中,名称
      b
      是回弹的,而在
      f1
      中,对象
      l
      是变异的

      在f1中,您将值存储在一个数组中,或者更好的是,在Python中存储一个列表,在f2中,您将对传递的值进行操作。这就是我对它的解释。我可能错了

      这在一篇文章中有详细介绍,但我将尝试在您的特定上下文中解释这个问题


      当你声明你的函数时,默认参数在那一刻被计算。它不会在每次调用函数时刷新

      函数行为不同的原因是您对待它们的方式不同。在
      f1
      中,您正在变异对象,而在
      f2
      中,您正在创建一个新的整数对象并将其分配到
      b
      。您不是在修改
      b
      ,而是在重新分配它。它现在是一个不同的对象。在
      f1
      中,您可以将相同的对象保留在周围

      考虑另一个功能:

      #!/usr/bin/env python3.2
      
      def f1(a, l=[]):
          l.append(a)
          return(l)
      
      print(f1(1))
      print(f1(1))
      print(f1(1))
      
      def f2(a, b=1):
          b = b + 1
          return(a+b)
      
      print(f2(1))
      print(f2(1))
      print(f2(1))
      
      其行为类似于
      f2
      ,不会一直附加到默认列表。这是因为它正在创建一个新的
      l
      ,而从未修改默认参数中的对象


      python中的常见样式是分配默认参数
      None
      ,然后分配一个新列表。这就绕过了这个模棱两可的问题

      def f3(a, l= []):
         l = l + [a]
         return l
      

      这是一个有点棘手的案件。当您很好地理解Python如何处理名称和对象时,这是有意义的。如果您正在学习Python,您应该努力尽快理解它,因为它绝对是您在Python中所做一切的核心

      Python中的名称类似于
      a
      f1
      b
      。它们仅存在于特定范围内(即,您不能在使用它的函数之外使用
      b
      )。在运行时,名称引用一个值,但可以随时使用赋值语句恢复为新值,如:

      def f1(a, l = None):
         if l is None:
             l = []
      
         l.append(a)
      
         return l
      
      值是在程序中的某个点创建的,可以通过名称引用,也可以通过列表或其他数据结构中的插槽引用。在上面的示例中,名称
      a
      绑定到值5,然后反弹到值7。这对5没有影响,无论当前绑定了多少个名称,该值始终是值5

      另一方面,对
      b
      的赋值使
      b
      a
      在该时间点引用的值绑定。随后重新绑定名称
      a
      5没有影响,因此对名称
      b
      没有影响,后者也绑定到值5

      赋值在Python中总是这样工作的。它从来不会对值产生任何影响。(除了某些对象包含“名称”;重新绑定这些名称显然会影响包含名称的对象,但不会影响名称在更改之前或之后引用的值)

      每当您在赋值语句的左侧看到一个名称时,您就是在(重新)绑定该名称。无论何时在任何其他上下文中看到名称,您都在检索该名称所引用的(当前)值


      这样,我们就可以看到您的示例中发生了什么

      当Python执行函数定义时,它会计算用于默认参数的表达式,并将它们隐藏在一旁。在此之后:

      a = 5
      b = a
      a = 7
      
      l
      不是什么,因为
      l
      只是函数
      f1
      范围内的一个名称,而我们不在该函数内。但是,值
      []
      存储在某个地方

      当Python执行转换为对
      f1
      的调用时,它会将所有参数名(
      a
      l
      )绑定到适当的值—调用者传入的值或定义函数时创建的默认值。因此,当Python执行调用时,
      f3(5)
      ,名称
      a
      将绑定到值5,名称
      l
      将绑定到我们的默认列表

      当Python执行
      l.append(a)
      时,看不到赋值,因此我们引用的是
      l
      a
      的当前值。因此,如果这要对
      l
      产生任何影响,它只能通过修改
      l
      引用的值来实现,事实上它确实如此。列表的
      append
      方法通过在末尾添加项目来修改列表。因此在此之后,我们的列表值(仍然是存储为
      f1
      的默认参数的相同值)现在已附加了5(当前值
      a
      ),看起来像
      [5]

      然后我们返回
      l
      。但是我们已经修改了默认列表,因此它将影响将来的任何调用。而且,我们已经返回了默认列表,因此对返回值的任何其他修改都将影响将来的任何调用

      现在,考虑<代码> F2< /代码>:

      def f1(a, l=[]):
          l.append(a)
          return(l)
      
      在这里,与前面一样,值1被存储在某个地方,用作
      b
      的默认值,当我们开始执行
      f2(5)
      调用时,名称
      a
      将绑定到参数5,并且名称
      b
      def f2(a, b=1):
          b = b + 1
          return(a+b)
      
      x += y
      
      x = x + y