奇怪的变量操纵行为

时间:2013-08-27 23:51:01

标签: python

当我有像

这样的功能时
def foo(A):
    tmp=A
    tmp=tmp+1
    *rest of the function*
    return

def foo(A):
    global tmp
    tmp=A
    tmp=tmp+1
    *rest of the function*
    return

将“A”和“tmp”1都添加到“tmp”而不是“tmp”。我做错了什么,我该如何解决?

2 个答案:

答案 0 :(得分:0)

正如nneonneo在Blake的回答(描述问题的重要部分)所述的评论中指出的那样,原始帖子中的代码实际上并没有按照他的陈述行事。例如:

def foo(A):
   tmp = A
   tmp = tmp + 1
   return (A, tmp)

foo(3)

返回(3,4),意思是A保持不变。

如果A不是真的,那么A是一个可变类型。可变类型包括列表,字典和派生类型,而整数,浮点数和元组不可变。

例如:

def foo(A):
   tmp = A
   tmp[0] = tmp[0] + 1
   return (A, tmp)

foo([1, 2])

返回([2, 2], [2, 2]),在这种情况下A已更改。

foo在列表情况下改变了A的值,但不是整数情况,因为列表是可变的而整数则不是。当A是可变类型时,将A分配给tmp会为可变对象分配引用,并且更改其中一个元素(如tmp[0] = tmp[0] + 1中)不会生成新对象。

如果您不希望函数对列表具有类似副作用的行为,例如,常见的Python习惯用法是使用切片表示法来复制列表。当您将它分配给作为A:

中列表对象的副本的tmp时,这将生成一个新的列表对象
def foo(A):
   tmp = A[:]
   # this slice makes a new list, a copy of A

   tmp[0] = tmp[0] + 1
   return (A, tmp)

foo([1, 2])

返回([1, 2], [2, 2]),因此A未更改且tmp已更改。

还有其他方法可以复制彼此略有不同的列表或其他可变对象。 How to clone or copy a list?对您的选择有很好的描述。

答案 1 :(得分:-1)

那是因为python方法参数是通过引用传递的,而不是通过值传递的。你基本上修改了内存中的相同位置,两个不同的变量指向。

>>> def foo(a):
    tmp = a
    print(tmp, a, id(a), id(tmp))
>>> foo(5)
5 5 505910928 505910928
>>> b = 5
>>> foo(b)
5 5 505910928 505910928
>>> id(b)
505910928

以全球为例:

>>> def foo(a):
    global tmp
    a = tmp
    print(a, tmp, id(a), id(tmp))
>>> foo(5)
7 7 505910960 505910960
>>> foo('s')
7 7 505910960 505910960
>>> tmp
7
>>> tmp = 6
>>> foo('a')
6 6 505910944 505910944
相关问题