如果我使用列表作为函数的参数,我希望原始列表不会被修改。为什么当我使用下面的代码时,当{em> x == z
为真时,x == range(10)
为True?
In [83]: def pop_three(collection):
....: new_collection = []
....: new_collection.append(collection.pop())
....: new_collection.append(collection.pop())
....: new_collection.append(collection.pop())
....: return new_collection, collection
....:
In [84]: x = range(10)
In [85]: x
Out[85]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [86]: y, z = pop_three(x)
In [87]: y
Out[87]: [9, 8, 7]
In [88]: z
Out[88]: [0, 1, 2, 3, 4, 5, 6]
In [89]: x
Out[89]: [0, 1, 2, 3, 4, 5, 6]
答案 0 :(得分:3)
如果我使用列表作为函数的参数,我希望原始列表不会被修改。
没有。我认为你在这里缺少的是Python永远不会自动复制任何东西。
如果您习惯使用像C ++这样的语言,那么Python就非常不同了。 Ned Batchelder一如既往地解释了这一点,但让我总结一下:
a = b
或调用f(b)
时,会将内存位置b
中的值复制到内存位置a
(可能调用转换运算符或转换构造函数或复制构造函数或复制赋值运算符 - 或移动那些一半的版本......但我们不是在这里了解C ++的复杂性。)a = b
或致电f(b)
时,只会为同一个对象创建另一个名称。特别是在您的情况下,collection
和x
是同一对象的名称。如果您在通话前添加print(id(collection))
并在功能内添加了print(id(x))
,则会同时打印相同的号码。
所以,在Python中,如果你想要一个副本,你必须明确地要求它 - 例如,pop_three(x[:])
或pop_three(copy.copy(x))
。
或者,当然,你可以在pop_three
内完成。
或者,最重要的是,你可以首先避免使用像pop
这样的变异方法:
def pop_three(collection):
return collection[-3:][::-1], collection[:-3]
我很困惑,因为传递给函数的字符串或整数可以这种方式处理。
嗯,他们可以按照这种方式处理,就像列表一样。如果你从不改变任何东西,单独的副本和共享引用之间的区别是无关紧要的。*因为Python字符串和整数是不可变的,所以任何带有字符串或整数的代码都不能出现区别。另一方面,列表是可变的,因此区分可以出现 - 但是完全可能,实际上通常最好,编写使用它们而不会改变任何内容的代码,如上面的最后一个例子
请注意,这假定了上面的第一点:与C ++赋值不同,Python赋值不是一种突变形式。但它的边缘可能会变得棘手。例如,x[0] = 1
是一个突变吗?嗯,它不是x[0]
的变异,而是x
的变异。那么x += y
呢?语言留下了x
的类型,对于可变类型,它通常(但不总是)是一个变异,而对于不可变类型,当然不是。
*这不是真的;您可以编写依赖于身份的代码,即使它不相关,例如,使用id
函数或is
运算符。这样的代码几乎不是Pythonic,或者是一个好主意......但它可以帮助学习如何工作。尝试使用print(id(x))
进行上述x = "a" + "b"
建议。但是,这可能会产生误导,因为Python解释器被允许“实习”它知道保证不可变的对象,并且它使用例如小整数来实现,并允许Python编译器折叠常量,并且它例如,使用文字字符串。
答案 1 :(得分:1)
因为当您将x
传递给pop_tree()并且您调用collection.pop()
时。这有效地做了x.pop()
因此当你从函数转向时,x只有7个元素
答案 2 :(得分:0)
z = pop_three(x)
表示您传递了列表x
,然后使用x
collection.pop()
更改了该列表x
,因此x
正在变异因此不能是== range(10)
y
变为new_collection
,z
变为collection
,这是x
的变异返回值。
In [2]: x = range(10)
In [3]: y, z = pop_three(x)
In [4]: z is x # z is the object x
Out[4]: True
答案 3 :(得分:0)
列表是可变的。从列表中弹出时,可以修改列表。
最初指向列表的任何变量将继续指向相同的修改列表。您在列表中指向的任何新变量也将指向相同的修改列表。