为什么python中的list操作在函数范围之外运行?

Why do list operations in python operate outside of the function scope?

本问题已经有最佳答案,请猛点这里访问。

在下面的python代码中,变量number传递给函数addone,并对本地副本进行操作。数字的值保持不变。

1
2
3
4
5
6
7
8
def addone(num):
    num = num + 1
    print"function: added 1, now %d" % num

number = 5
print"Before:", number
addone(number)
print"After:", number

输出:

1
2
3
Before: 5
function: added 1, now 6
After: 5

但是,该行为似乎与诸如pop、append等列表操作不同。这让我有些困惑。所有列表操作是否在全球范围内运行?如果是这样,背后有什么特别的原因吗?

1
2
3
4
5
6
7
8
def pop_first(stuff):
    popped = stuff.pop(0)
    print"function: '%s' was popped!" % popped

words = ["A","list","of","words"]
print"Before:", words
pop_first(words)
print"After:", words

输出:

1
2
3
Before: ['A', 'list', 'of', 'words']
function: 'A' was popped!
After: ['list', 'of', 'words']


简短的答案是因为列表是可变的,整数是不可变的。

不能在适当的位置改变整数,所以我们称之为"不可变"。考虑到这一点,像在整数上加法这样的事情不会修改原始对象,而是返回一个新的值-因此原始变量将保持不变。因此,如果我们存储一个对整数的引用,那么只要我们没有更改它们中的任何一个,它们就只是同一个对象:

1
2
3
4
5
6
7
8
9
10
11
12
>>> foo = 1
>>> bar = foo
>>> foo is bar
True
>>> foo += 2
3
>>> foo
3
>>> bar
1
>>> foo is bar
False

另一方面,列表是"可变的"(可以修改同一个对象引用),像pop()这样的操作会使list发生突变,从而更改原始对象。这也意味着,如果编辑对可变对象(如list)的引用,原始对象也将更改:

1
2
3
4
5
6
7
8
9
10
11
12
>>> baz = [1, 2, 3, 4, 5]
>>> qux = baz
>>> qux is baz
True
>>> baz.pop()
5
>>> qux
[1, 2, 3, 4]
>>> baz
[1, 2, 3, 4]
>>> qux is baz
True

将对象传递给函数的方式与分配对象的方式相同。所以,你看到的效果和这个一样:

1
2
3
4
5
6
>>> words = ["A","list","of","words"]
>>> stuff = words
>>> stuff.pop()
'words'
>>> words
['A', 'list', 'of']

这是因为stuffwords是同一个列表,pop更改了该列表。int是不可变的,这意味着它们不支持任何就地的突变:每次更改其值时,它都会给您一个具有新值的不同int对象。您可以使用is操作符来测试两个对象是相同的还是不同的:

1
2
3
4
5
6
7
8
9
>>> stuff is words
True
>>> a = 5
>>> b = a
>>> a is b
True
>>> b += 1
>>> a is b
False


当执行stuff.pop()时,修改对象stuff。在执行num = num + 1操作时,如果不修改num,只需创建一个新对象并将其分配给变量num。如果num是一个列表,结果将完全相同:

1
2
3
4
5
6
7
8
9
10
11
12
13
def addone(num):
    num = num + [1]
    print"function: added 1, now", num

number = [5]
print"Before:", number
addone(number)
print"After:", number


# Before: [5]
# function: added 1, now [5, 1]
# After: [5]