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