Python变量范围(通过引用或复制传递?)

时间:2011-03-08 14:57:33

标签: python scope

为什么变量L在sorting(L)函数调用中被操纵?在其他语言中,L的副本将作为副本传递给sorting(),以便x的任何更改都不会更改原始变量?

def sorting(x):
    A = x #Passed by reference?
    A.sort() 

def testScope(): 
    L = [5,4,3,2,1]
    sorting(L) #Passed by reference?
    return L

>>> print testScope()

>>> [1, 2, 3, 4, 5]

4 个答案:

答案 0 :(得分:15)

长话短说:Python使用pass-by-value,但是通过值传递的东西是引用。实际对象有0到无穷大引用指向它们,并且为了改变该对象,无论你是谁以及如何获得对象的引用都无关紧要。

逐步完成您的示例:

  • L = [...]在内存中的某处创建一个list对象,局部变量L存储对该对象的引用。
  • sorting(严格地说,可调用对象指向全局名称sorting)使用L存储的引用副本进行调用,并将其存储在本地调用的本地x
  • 调用sort中包含的引用所指向的对象的方法x。它也获得对象的引用(在self参数中)。它以某种方式改变了该对象(对象,而不是对对象的一些引用,它只是一个内存地址)。
  • 现在,由于引用是复制的,而不是引用所指向的对象,因此我们讨论的所有其他引用仍然指向相同的对象。 “就地”修改了一个对象。
  • testScope然后返回对该列表对象的另一个引用。
  • print使用它来请求字符串表示(调用__str__方法)并输出它。因为它仍然是同一个对象,当然它正在打印排序列表。

因此,无论何时将对象传递到任何地方,都可以与任何人共享。函数可以(但通常不会)改变它们被传递的对象(由引用指向),从调用变异方法到赋值成员。请注意,分配成员与分配普通ol'名称不同 - 这仅仅意味着改变本地范围,而不是任何调用者的对象。所以你不能改变调用者的本地人(这就是为什么它不是传递参考)。

进一步阅读:A discussion on effbot.org为什么它不是通过引用传递而不是大多数人所谓的传值。

答案 1 :(得分:9)

Python具有Mutable和Immutable objects的概念。像字符串或整数这样的对象是不可变的 - 您所做的每个更改都会创建一个新的字符串或整数。

列表是可变的,可以在适当的位置进行操作。见下文。

a = [1, 2, 3]
b = [1, 2, 3]
c = a

print a is b, a is c
# False True

print a, b, c
# [1, 2, 3] [1, 2, 3] [1, 2, 3]
a.reverse()
print a, b, c
# [3, 2, 1] [1, 2, 3] [3, 2, 1]
print a is b, a is c
# False True

注意c是如何反转的,因为c“是”a。有许多方法可以将列表复制到内存中的新对象。一种简单的方法是切片:c = a[:]

答案 2 :(得分:1)

在文档中特别提到.sort()函数会改变集合。如果要迭代已排序的集合,请使用sorted(L)。这提供了一个生成器,而不仅仅是对列表进行排序。

答案 3 :(得分:0)

a = 1
b = a
a = 2
print b

引用与单独的对象不同。

.sort()也会改变集合。