两段Python代码的区别
我正在做一个练习,内容如下:
# B. front_x
# Given a list of strings, return a list with the strings
# in sorted order, except group all the strings that begin with 'x' first.
# e.g. ['mix', 'xyz', 'apple', 'xanadu', 'aardvark'] yields
# ['xanadu', 'xyz', 'aardvark', 'apple', 'mix']
# Hint: this can be done by making 2 lists and sorting each of them
# before combining them.
示例解决方案:
def front_x(words):
listX = []
listO = []
for w in words:
if w.startswith('x'):
listX.append(w)
else:
listO.append(w)
listX.sort()
listO.sort()
return listX + listO
我的解决方案:
def front_x(words):
listX = []
for w in words:
if w.startswith('x'):
listX.append(w)
words.remove(w)
listX.sort()
words.sort()
return listX + words
在我测试我的解决方案时,结果有点奇怪。这里是我解决方案的源代码:http://dl.dropbox.com/u/559353/list1.py。你可以试试看。
4 个回答
0
在遍历一个列表的时候,如果你同时对这个列表进行修改,会导致一些不可预知的结果。这就是为什么示例中会创建两个新列表,而不是直接从原列表中删除元素。
for w in words:
if w.startswith('x'):
listX.append(w)
words.remove(w) # Problem here!
你可以查看 这个问题,里面讨论了这个问题。简单来说,列表的迭代器在遍历列表的索引时,并不会回头检查是否有修改(这样做会很耗费资源!)。
如果你不想创建第二个列表,那你就需要进行两次遍历。第一次遍历 words
来创建 listX
,第二次遍历 listX
来从 words
中删除元素。
1
主要有两个不同之处:
- 在循环中从一个正在遍历的列表中删除元素,在Python里并不太好使。如果你用的是Java,系统会报错,告诉你不能在遍历一个集合的时候去修改它。而在Python中,似乎不会直接给你这个错误。@Felix_Kling在他的回答中解释得很清楚。
- 另外,你在修改输入参数
words
。这意味着调用你函数front_x
的人会看到words
在函数执行后被修改了。除非这是明确预期的行为,否则最好避免这种情况。想象一下,如果你的程序在别的地方也在使用words
,那就会很麻烦。像sample solution
中那样保持两个列表会是更好的做法。
3
问题在于你在遍历列表的时候,同时又在删除里面的元素(也就是在修改它):
for w in words:
if w.startswith('x'):
listX.append(w)
words.remove(w)
举个例子:
>>> a = range(5)
>>> for i in a:
... a.remove(i)
...
>>> a
[1, 3]
这段代码的运行过程如下:
- 先获取第一个元素,然后把它删除。
- 接着移动到下一个元素。但因为我们刚才删除了
0
,所以现在1
变成了新的第一个元素。这样下一个元素就变成了2
,而1
就被跳过了。 - 同样的情况也发生在
3
和4
上。