我将此函数定义为:[1,2,3] - > [2,3,1]
def shift_to_left(p):
p.append(p[0])
return p[1:]
当我这样检查时,结果还可以:
p1 = [1,2,3]
print p1
p1 = shift_to_left(p1)
print p1
The result:
[1, 2, 3]
[2, 3, 1]
但是,当我引入另一个列表并连接时,结果是不同的:
ss = []
p1 = [1,2,3]
ss.append(p1)
p1 = shift_to_left(p1)
ss.append(p1)
print ss
The result
[[1, 2, 3, 1], [2, 3, 1]]
But I want:
[1,2,3]
[2,3,1]
为什么会这样?
非常感谢,
答案 0 :(得分:4)
如果你想在列表中移动/旋转元素,我认为更好的方法是使用deque,而不是重新发明轮子。例如:
from collections import deque
d = deque([1,2,3])
d.rotate(-1)
print(d)
#[2, 3, 1]
答案 1 :(得分:4)
在Python中,大多数参数都是通过引用获得的。
你的函数shift_to_left
实际上改变了它的参数(通过使用append),但随后返回一个切片(这是列表的浅表副本)。
当您使用shift_to_left
的输出替换原始变量时,此行为将被隐藏:
In [1]: def shift_to_left(p):
...: p.append(p[0])
...: return p[1:]
...:
In [2]: xs = [1, 2, 3]
In [3]: xs = shift_to_left(xs)
In [4]: xs
Out[4]: [2, 3, 1]
但是如果我们将结果分配给 new 变量,我们可以看到原始列表确实已被更改:
In [5]: ys = shift_to_left(xs)
In [6]: ys
Out[6]: [3, 1, 2]
In [7]: xs
Out[7]: [2, 3, 1, 2]
我们的结果ys
是从第二个元素开始的xs
切片。这就是你的期望。
但xs
本身的也已被append
调用更改:现在它比以前更长一个元素。
这就是你在第二个例子中遇到的情况。
如果你不想要这种行为,一种避免这种行为的方法是将你的列表副本传递给shift_to_left
:
In [8]: zs = shift_to_left(ys[:])
In [9]: zs
Out[9]: [1, 2, 3]
In [10]: ys
Out[10]: [3, 1, 2]
在这里,您可以看到原始列表ys
尚未被修改,因为shift_to_left
被赋予了它的副本,而不是对象本身。 (当然,这仍然是通过引用传递的;它不是对ys
)的引用。
或者,可能更合理的是,您可以更改shift_to_left
本身,以便它不会修改其参数:
def shift_to_left(xs):
return xs[1:] + xs[0] # build a new list in the return statement
这两种方法的最大问题在于它们会创建大量的列表副本,当列表很大时,列表的速度会非常慢(并且使用大量内存)。
当然,正如@Marcin指出的那样,如果这不仅仅是一个学术练习,你应该使用其中一个内置数据结构,例如deque
。
答案 2 :(得分:3)
如果您运行代码here,您会注意到ss
仍然指向p.append(p[0])
的{{1}}副本的原始版本(由于p1
而在您的班次函数中发生变异),当p1
重新分配时,p
指向知道列表,从而导致行为。 (11中的第10步)
(ss[0] = p
变异,p1
)
(ss
完全分配到新列表,后者附加到{{1}})
答案 3 :(得分:1)
为什么会这样?
return p[1:]
是“非破坏性的”:它会创建一个新列表。但是,p.append(p[0])
具有“破坏性”:它会自行更改p
。
首先,您将p1
追加到ss
。这使[[1, 2, 3]]
成为[1, 2, 3]
p1
。
然后执行shift_to_left
,将p1
更改为[1, 2, 3, 1]
并返回[2, 3, 1]
。由于p1
中包含ss
,因此ss
变为[[1, 2, 3, 1]]
,然后您将新的p1
附加到[[1, 2, 3, 1], [2, 3, 1]]
。
更好的实施将完全是非破坏性的:
def shift_to_left(p):
return p[1:] + [p[0]]
答案 4 :(得分:0)
试试这个:
p1 = [1,2,3]
p1 = shift_to_left(p1)
ss = []
ss.extend(p1)
print ss
打印[2, 3, 1]
。请改用extend()
,因为append()
将在数组中创建一个数组。你还额外打电话给ss.append(p1)
。