Esta resposta foi originalmente escrita em resposta a uma pergunta que foi marcada como duplicada:
Removendo coordenadas da lista em python
Existem dois problemas no seu código:
1) Ao usar remove (), você tenta remover números inteiros, ao passo que precisa remover uma tupla.
2) O loop for ignorará os itens da sua lista.
Vamos analisar o que acontece quando executamos seu código:
>>> L1 = [(1,2), (5,6), (-1,-2), (1,-2)]
>>> for (a,b) in L1:
... if a < 0 or b < 0:
... L1.remove(a,b)
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError: remove() takes exactly one argument (2 given)
O primeiro problema é que você está passando 'a' e 'b' para remove (), mas remove () aceita apenas um único argumento. Então, como podemos fazer com que remove () funcione corretamente com sua lista? Precisamos descobrir o que é cada elemento da sua lista. Nesse caso, cada um é uma tupla. Para ver isso, vamos acessar um elemento da lista (a indexação começa em 0):
>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>
Aha! Cada elemento de L1 é na verdade uma tupla. Então é isso que precisamos passar para remover (). Tuplas em python são muito fáceis, elas são simplesmente feitas colocando valores entre parênteses. "a, b" não é uma tupla, mas "(a, b)" é uma tupla. Então, modificamos seu código e o executamos novamente:
# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))
Esse código é executado sem nenhum erro, mas vamos olhar para a lista que ele gera:
L1 is now: [(1, 2), (5, 6), (1, -2)]
Por que (1, -2) ainda está na sua lista? Acontece que modificar a lista enquanto usa um loop para iterar sobre ela é uma péssima idéia sem cuidados especiais. O motivo pelo qual (1, -2) permanece na lista é que os locais de cada item na lista foram alterados entre as iterações do loop for. Vamos ver o que acontece se alimentarmos o código acima com uma lista mais longa:
L1 = [(1,2),(5,6),(-1,-2),(1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
### Outputs:
L1 is now: [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]
Como você pode deduzir desse resultado, sempre que a instrução condicional for avaliada como verdadeira e um item da lista for removido, a próxima iteração do loop ignorará a avaliação do próximo item da lista porque seus valores agora estão localizados em índices diferentes.
A solução mais intuitiva é copiar a lista, iterar sobre a lista original e modificar apenas a cópia. Você pode tentar fazer o seguinte:
L2 = L1
for (a,b) in L1:
if a < 0 or b < 0 :
L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
print L2 is L1
del L1
L1 = L2; del L2
print ("L1 is now: ", L1)
No entanto, a saída será idêntica à anterior:
'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]
Isso ocorre porque, quando criamos o L2, o python não criou um novo objeto. Em vez disso, apenas referenciou L2 ao mesmo objeto que L1. Podemos verificar isso com 'is', que é diferente de meramente "igual" (==).
>>> L2=L1
>>> L1 is L2
True
Podemos fazer uma cópia verdadeira usando copy.copy (). Então tudo funciona como esperado:
import copy
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
L2 = copy.copy(L1)
for (a,b) in L1:
if a < 0 or b < 0 :
L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
del L1
L1 = L2; del L2
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]
Finalmente, há uma solução mais limpa do que ter que fazer uma cópia totalmente nova de L1. A função reversed ():
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
for (a,b) in reversed(L1):
if a < 0 or b < 0 :
L1.remove((a,b))
print ("L1 is now: ", L1)
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]
Infelizmente, não posso descrever adequadamente como reversed () funciona. Retorna um objeto 'listreverseiterator' quando uma lista é passada para ele. Para fins práticos, você pode pensar nisso como criar uma cópia invertida de seu argumento. Esta é a solução que eu recomendo.