2013-01-02 18 views
6

Mỗi lần tôi chạy chương trình này, tôi nhận được lỗi này:Python 2,7 ném ValueError: list.remove (x): x không có trong danh sách

ValueError: list.remove(x): x not in list 

Tôi cố gắng để làm giảm sức khỏe của một người ngoài hành tinh duy nhất bất cứ khi nào nó bị trúng một tia. Người nước ngoài độc thân đó cũng nên bị phá hủy nếu sức khỏe của nó là <= 0. Tương tự, bu lông cũng sẽ bị phá hủy. Đây là mã của tôi:

def manage_collide(bolts, aliens): 
    # Check if a bolt collides with any alien(s) 
    for b in bolts: 
     for a in aliens: 
      if b['rect'].colliderect(a['rect']): 
       for a in aliens: 
        a['health'] -= 1 
        bolts.remove(b) 
        if a['health'] == 0: 
         aliens.remove(a) 
    # Return bolts, aliens dictionaries 
    return bolts, aliens 

ValueError xảy ra trên dòng aliens.remove(a). Chỉ cần làm rõ, cả hai aliensbolts là danh sách các từ điển.

Tôi đang làm gì sai?

+0

ValueError trên dòng nào? – asheeshr

+0

aliens.remove (a) –

+0

Để tham khảo trong tương lai, vấn đề với mã này là tôi lặp lại danh sách người ngoài hành tinh hai lần, điều này gây ra một số vấn đề khi cố gắng xóa khỏi danh sách. Loại bỏ 'thứ hai cho người ngoài hành tinh' thứ hai sẽ ngăn chặn vấn đề này. –

Trả lời

14

Bạn không nên xóa các mục khỏi danh sách bạn đang lặp lại. Tạo một bản sao thay vì:

for a in aliens[:]: 

for b in bolts[:]: 

Sửa đổi một danh sách trong khi vòng lặp trên nó, ảnh hưởng đến vòng lặp:

>>> lst = [1, 2, 3] 
>>> for i in lst: 
...  print i 
...  lst.remove(i) 
... 
1 
3 
>>> lst 
[2] 

mục Loại bỏ khỏi danh sách bạn đang looping hơn hai lần làm những thứ phức tạp hơn một chút, dẫn đến một ValueError:

>>> lst = [1, 2, 3] 
>>> for i in lst: 
...  for a in lst: 
...   print i, a, lst 
...   lst.remove(i) 
... 
1 1 [1, 2, 3] 
1 3 [2, 3] 
Traceback (most recent call last): 
  File "<stdin>", line 4, in <module> 
ValueError: list.remove(x): x not in list 

Khi tạo một bản sao của danh sách mà bạn đang thay đổi tại mỗi cấp của các vòng của bạn, bạn tránh được những vấn đề:

>>> lst = [1, 2, 3] 
>>> for i in lst[:]: 
...  for i in lst[:]: 
...   print i, lst 
...   lst.remove(i) 
... 
1 [1, 2, 3] 
2 [2, 3] 
3 [3] 

Khi bạn có một vụ va chạm, bạn chỉ cần loại bỏ các b tia lần, không phải trong vòng lặp mà bạn làm tổn thương người ngoài hành tinh. Xóa sạch người ngoài hành tinh một cách riêng biệt sau:

def manage_collide(bolts, aliens): 
    for b in bolts[:]: 
     for a in aliens: 
      if b['rect'].colliderect(a['rect']) and a['health'] > 0: 
       bolts.remove(b) 
       for a in aliens: 
        a['health'] -= 1 
    for a in aliens[:]: 
     if a['health'] <= 0: 
      aliens.remove(a) 
    return bolts, aliens 
+1

Điều này không thực sự trả lời câu hỏi của OP. Nó không thực sự là một vấn đề để loại bỏ các mục từ một danh sách trong khi lặp qua nó; nó chỉ là nó có thể tạo ra kết quả bất ngờ nếu bạn không biết nó hoạt động như thế nào. – kindall

+0

Nó vẫn đặt một ValueError trên cùng một dòng aliens.remove (a) khi chỉ thay đổi dòng đó thành một danh sách sao chép. –

+0

@kindall: Đó là các vòng lặp đôi khiến mọi thứ thú vị hơn và có thể dẫn đến lỗi giá trị. –

1

Có lỗi trong mã của bạn đang gây ra lỗi này. mã của bạn, đơn giản, trông giống như:

for b in bolts: 
    for a in aliens: 
    for a in aliens: 
     bolts.remove(b) 

Đó là làm cho bạn để lặp qua aliens nhiều lần cho mỗi mục trong b. Nếu b được loại bỏ trên vòng đầu tiên qua aliens thì khi nó lặp lại nó lần thứ hai, bạn sẽ gặp phải lỗi đó.

Một vài điều cần khắc phục. Trước hết, thay đổi trong vòng lặp bên trên aliens sử dụng một cái gì đó khác hơn a, vì vậy:

for b in bolts: 
    for a in aliens: 
    for c in aliens: 
     if hit: 
     bolts.remove(b) 

Thứ hai, chỉ loại bỏ b từ bolts một lần. như vậy:

for b in bolts: 
    for a in aliens: 
    should_remove = False 
    for c in aliens: 
     if hit: 
     should_remove = True 
    if should_remove: 
     bolts.remove(b) 

Có những vấn đề khác với mã này, tôi nghĩ, nhưng đó là nguyên nhân chính gây ra vấn đề của bạn. Bài đăng của Martijn cũng có thể hữu ích.

0

Đặt các bu lông cũng là "sức khỏe", được khởi tạo thành 1.Sau đó, bạn có thể thực hiện một vòng lặp lồng nhau để tính toán tất cả các thiệt hại và hai "vòng lặp" không cần thiết riêng biệt để loại bỏ mọi thứ "chết". Ngoại trừ, đừng làm như vậy, bởi vì bạn vẫn không muốn sửa đổi danh sách mà bạn đang lặp lại. Tạo bản sao vẫn quá phức tạp. Những gì bạn thực sự muốn làm là trực tiếp xây dựng một danh sách mới chỉ những thứ "còn sống" và bạn có thể làm điều đó một cách mô tả với tính năng hiểu danh sách (hoặc như được hiển thị ở đây, với filter).

# for example 
class Alien: 
    # ... other stuff 
    def damage(self): self.hp -= 1 
    def alive(self): return self.hp > 0 

# similarly for Bolt 

def collide(an_alien, a_bolt): 
    # etc. 

def handle_collisions(aliens, bolts): 
    for a in aliens: 
     for b in bolts: 
      if collide(a, b): 
       a.damage() 
       b.damage() 

    return list(filter(Alien.alive, aliens)), list(filter(Bolt.alive, bolts))