奇怪的Python范围问题

时间:2016-04-16 06:39:46

标签: python scope

我认为我很了解Python变量范围,但是今天我遇到了这个代码。

from __future__ import print_function

def main():
    v_Matrix =[[1, 2, 3],
               [4, 5, 6],
               [7, 8, 9]]

    print(v_Matrix)
    print()

    f_Rotate(v_Matrix)
    print(v_Matrix)

    hh = 3
    f_This(hh)
    print(hh)

def f_Swap(v_Matrix, r1, c1, r2, c2):
    v_Matrix[r1][c1], v_Matrix[r2][c2] = v_Matrix[r2][c2], v_Matrix[r1][c1]

def f_Transpose(v_Matrix):
    for row in range(len(v_Matrix)):
        for col in range(row):
            f_Swap(v_Matrix, row, col, col, row)

def f_FlipVertical(v_Matrix):
    v_Size = len(v_Matrix)
    for row in range(v_Size // 2):
        for col in range(v_Size):
            f_Swap(v_Matrix, row, col, v_Size - row - 1, col)

def f_Rotate(v_Matrix):
    f_Transpose(v_Matrix)
    f_FlipVertical(v_Matrix)

def f_This(hh):
    hh = hh * 2

if __name__ == '__main__':
    main()

运行时,变量v_Matrix似乎表现得像全局一样。但是,测试变量hh的行为符合预期,其中一个范围位于main(),另一个范围位于f_This

v_Matrix不是全局的,在各种函数中被修改,但不在这些函数之间来回传递,甚至返回main()。然而,在v_Matrix范围内可以访问这些函数中应用于main()的值更改,如输出之间所示。但是,正如预期的那样,测试变量hh的值在main()范围内不会发生变化,只会在函数范围内发生变化。

是什么给出了?

2 个答案:

答案 0 :(得分:2)

Python中的所有东西都是一个对象,无论它们是可变的还是不可变的,对象都以相同的方式传递给函数。但是,可以在函数外部看到对可变对象的更改。

示例:

def f(c,d):
    print('Inside f()')
    print('  id(a) =',id(a),'value =',a)
    print('  id(b) =',id(b),'value =',b)
    print('  id(c) =',id(c),'value =',c)
    print('  id(d) =',id(d),'value =',d)
    c = 4     # local name c is assigned a new object.
    d[0] = 5  # local name d's object is mutated
    print('  id(a) =',id(a),'value =',a)
    print('  id(b) =',id(b),'value =',b) # b and d objects are same, so b changed
    print('  id(c) =',id(c),'value =',c) # id changed, not same as a
    print('  id(d) =',id(d),'value =',d) # id did not change, still same as b
    d = [6]   # local name d is assigned a new object.
    print('  id(d) =',id(d),'value =',d) # id changed, not same as b 
a = 3 # immutable
b = [3] # mutable
print('Before f()')
print('  id(a) =',id(a),'value =',a)
print('  id(b) =',id(b),'value =',b)
f(a,b)
print('After f()')
print('  id(a) =',id(a),'value =',a)
print('  id(b) =',id(b),'value =',b)

带注释的输出:

Before f()
  id(a) = 507107264 value = 3
  id(b) = 67001608 value = [3]
Inside f()
  id(a) = 507107264 value = 3
  id(b) = 67001608 value = [3]
  id(c) = 507107264 value = 3    # id(c) == id(a)
  id(d) = 67001608 value = [3]   # id(d) == id(b)
  id(a) = 507107264 value = 3
  id(b) = 67001608 value = [5]   # id(d)==id(b), so b changed when d did
  id(c) = 507107296 value = 4    # c was reassigned, id(c) != id(a)
  id(d) = 67001608 value = [5]   # id(d) == id(b)...object mutated
  id(d) = 65761864 value = [6]   # d was reassigned, id(d) != id(b)
After f()
  id(a) = 507107264 value = 3    # immutable a unaffected
  id(b) = 67001608 value = [5]   # sees mutation of list contents from d[0]=5

答案 1 :(得分:1)

list是一个可变数据结构。这意味着您可以在保持id()相同的同时更改其值。如果你传递一个命名这样一个对象的变量,因为它具有相同的id,它与你在代码的各个部分中引用的对象相同。因此,如果你在任何地方改变它,那就好了。

所以解决方案是,不要传递它们。而保持它和在数据转换中使用它(而不是变异),即创建另一个或更好的使用生成器,并仅评估最终所需列表。