2012-12-18 35 views
6

Tôi mới dùng Python và thử nghiệm với danh sách Tôi đang sử dụng Python 3.2.3 (mặc định, ngày 19 tháng 10 năm 2012, 20: 13:42), [GCC 4.6.3] trên linux2Tại sao vòng lặp for với phương thức pop (hoặc del statement) không lặp qua tất cả các phần tử danh sách

đây là samplecode tôi

>>> l=[1,2,3,4,5,6] 
>>> for i in l: 
...  l.pop(0) 
...  print(l) 
... 

tôi mong chờ những kết quả sau

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

Thay vào đó tôi nhận được

này
1 
[2, 3, 4, 5, 6] 
2 
[3, 4, 5, 6] 
3 
[4, 5, 6] 

Các điểm dừng vòng lặp lặp lại sau 3 lượt. Ai đó có thể giải thích tại sao?

+0

có thể trùng lặp của [Sửa đổi danh sách trong khi lặp lại] (http://stackoverflow.com/questions/1637807/modifying-list-while-iterating) –

+0

@NedBatchelder: Trong khi nguyên nhân gốc là như nhau, câu hỏi là khác nhau đáng kể . Lý do để gọi 'pop' thậm chí không giống nhau (liên kết đang cố gắng bỏ qua, cái này không phải là). – Guvante

Trả lời

5

unrolling một chút (các caret (^) nằm ở vòng "chỉ số"):

your_list = [1,2,3,4,5,6] 
      ^

sau popping ra khỏi mục đầu tiên:

your_list = [2,3,4,5,6] 
      ^

bây giờ tiếp tục vòng lặp:

your_list = [2,3,4,5,6] 
      ^

Bây giờ hãy tắt mục đầu tiên:

your_list = [3,4,5,6] 
      ^

Giờ hãy tiếp tục vòng lặp:

your_list = [3,4,5,6] 
       ^

Bây giờ bật tắt mục đầu tiên:

your_list = [4,5,6] 
       ^

Giờ hãy tiếp tục vòng lặp - Chờ đã, chúng tôi đã hoàn tất. :-)


>>> l = [1,2,3,4,5,6] 
>>> for x in l: 
...  l.pop(0) 
... 
1 
2 
3 
>>> print l 
[4, 5, 6] 
+2

Thật sao? Nó được đánh vần? Huh ... Tôi luôn nghĩ rằng nó được gọi là bởi vì nó trông giống như một củ cà rốt ngược ... Tìm hiểu một cái gì đó mới mỗi ngày ... – mgilson

1

Python không hỗ trợ thay đổi độ dài của danh sách trong khi bạn lặp lại nó. Thay vào đó, hãy làm việc trên bản sao hoặc sử dụng số list comprehension.

Hãy suy nghĩ về cách Python thực sự đang thực hiện vòng lặp for - nó đếm ngược qua các phần tử, trả về mục tại chỉ mục hiện tại. Khi bạn xóa một chỉ mục, chỉ mục có nghĩa là một phần tử khác.

+0

Trong một trường hợp, nó có thể hoạt động. Khi popping phần tử cuối cùng trên mỗi lần lặp. –

+0

Có khả năng xảy ra tình huống. Nó không phải là một cái gì đó bạn nên dựa vào tuy nhiên, có những cách tốt hơn. –

+2

Python hỗ trợ sửa đổi một danh sách trong khi lặp lại nó, và nó hoạt động theo một cách nhất quán và có thể đoán trước khi bạn hiểu những gì đang xảy ra. BTW, một giải pháp hữu ích khác cho một số trường hợp sử dụng là hoạt động trên danh sách theo thứ tự ngược lại. – kindall

2

Bạn phải cẩn thận khi cố gắng sửa đổi bộ sưu tập mà bạn đang lặp lại. Trong trường hợp này, danh sách theo dõi "vị trí hiện tại" với chỉ số nguyên đơn giản. Khi bạn sử dụng pop(), mọi thứ sẽ thay đổi chỉ mục và do đó các thành phần sẽ bị bỏ qua.

Trong lần lặp đầu tiên của vòng lặp, i là l [0]. Sau đó, bạn bật danh sách, sau đó bạn truy cập l [1], đó là những gì ban đầu là l [2]. Sau đó, bạn bật danh sách và truy cập lặp lại tiếp theo l [2], được sử dụng để ở l [4], v.v.

Không cần phải bật các phần tử trong mã này, có lẽ bạn đang làm điều gì đó phức tạp hơn trong mã thực của bạn.

-1

Bạn có thể sử dụng một vòng lặp while chứ không phải là một vòng lặp for cho nhiệm vụ này.

while len(some_list)>0 : 
    some_list.pop(0) 

Một vòng lặp for sẽ thực sự lặp qua mỗi mục trong danh sách, trong đó sẽ không hoạt động khi các chỉ số trong danh sách sẽ thay đổi theo từng xóa, và bạn sẽ không kết thúc nhận được tất cả các mặt hàng.

Tuy nhiên, vòng lặp while sẽ kiểm tra điều kiện mỗi lần vòng lặp chạy và nếu điều đó vẫn đúng, hãy chạy lại mã. Ở đây chúng tôi xác định rằng độ dài của danh sách phải lớn hơn 0, tức là phải có nội dung trong danh sách.