Why the default argument behaved globally immutable?
python中的default arguments直观地是局部作用域但全局可变的变量。
下面,为什么第二次调用my_sum的结果是20,尽管我希望它是30?
1 2 3 4 5 6 7 8 9 10 11
| def my_append(el, ar = []):
ar.append(el)
return ar
print my_append(10) # => [10]
print my_append(20) # => [10, 20]
def my_sum(i, sum = 0):
sum += i
return sum
print my_sum(10) # => 10
print my_sum(20) # => 20 |
- 因为整数是不可变的。
- 可变性不取决于它是否是关键字参数,而是取决于数据类型。列表是可变的,整数不是。使用sum += i时,没有任何int的变化,而是将sum分配给一个新的整数(sum + 1)。
- 扩展到"责备数据类型,而不是范围"—除了语法之外,python中列表和元组的关键区别在于列表是可变的,而元组是不可变的。两者都是保存值序列的复合类型。在列表中,可以替换其中一个值(列表的突变)。在一个元组中,你不能-如果你想要一个新的元组,它基本上是相同的,但是有一个元素改变了,你必须做一个全新的替换元组。
- 在非特定于Python的术语中,不可变值是具有值语义的实际值。可变值是通过可变引用引用元素的容器,因此可以更改引用以替换中的不同元素。不可变容器(如tuple)可能仍然保留对元素的引用,但由于容器是不可变的,因此对元素的引用不能改变。变量总是通过可变引用引用对象(可变或不可变),因此pythons普遍引用语义,如果您认为足够大,则可以替换不可变结构。
- 实际上,"因此Python普遍的参考语义"是错误的。由于许多有用的复合类型是可变的,所以pythons普遍存在的引用语义。我试图解释的是,在某一点上,你总是可以替换一个对象——如果你想改变的对象是不可变的,你可以替换包含它的对象,或者包含它的对象,等等——一旦你达到了局部/全局变量的级别,它的内容就可以被替换——就像那些简单的例子一样。可变整数。
为了有助于澄清这一点,请考虑这一行更改:
1 2 3 4 5 6 7
| def my_append(el, ar=[]):
ar = ar + [el]
# ar.append(el)
return ar
print(my_append(10)) # [10]
print(my_append(20)) # [20] |
因此,问题不在于可变性或不可变性,而在于第二个版本重新命名了名称。
这是一个比评论家们所说的更微妙的问题。int.__iadd__不存在,因此在整数的情况下,操作返回到sum = sum + i时,再次重新绑定名称。
然而,list.__iadd__确实存在,它使现有的对象发生变异。这就是您看到默认参数发生更改的原因。
- 函数参数和局部变量在python中是否有语义区别?在这种情况下,参数var已被分配左侧的本地var有效地隐藏。
- 在函数体内部,函数参数和局部变量在所有实际用途上都是相同的。所以当你重新绑定这个名字时,我想你可以说它隐藏了指向前一个对象的名字,是的。参数规范中的原始对象在函数内部和外部仍然是可访问的,因为它是包含在my_sum.func_defaults(my_sum.__defaults__on python3)中的第一项。
- 在这种情况下,他们不是。