2015-02-17 9 views
6

Sono un po 'perplesso dalla funzione python (2.7) list.remove. Nel documentation of remove si dice: "Rimuovi il primo elemento dall'elenco il cui valore è x. È un errore se non esiste tale elemento."Rimozione di un elemento da un elenco python, come vengono confrontati gli elementi (ad esempio array numpy)?

Quindi, credo che qui valore significa che il confronto si basa su uguaglianza (vale a dire ==) e non identità (vale a dire is). Tuttavia, qualcuno può spiegarmi il seguente comportamento. A quanto pare, entrambi i confronti sono usati, ma in un modo piuttosto strano:

import numpy as np 

x = np.array([1,2,3]) 
mylist = [x, 42, 'test', x] # list containing the numpy array twice 
print mylist 

Ciò, naturalmente, di stampa:

[array([1, 2, 3]), 42, 'test', array([1, 2, 3])] 

Fin qui tutto bene. Ma stranamente il seguente codice non esegue:

mylist.remove(x) 
print mylist 

dando

[42, 'test', array([1, 2, 3])] 

mi aspetterei a gettare un errore perché le matrici NumPy non restituiscono una dichiarazione booleana, ma una matrice booleana. Ad esempio, x == x restituisce array([ True, True, True], dtype=bool). Tuttavia, la nostra rimozione funziona felicemente. Tuttavia, chiamando la stessa dichiarazione ancora una volta produce il comportamento previsto:

mylist.remove(x) 

getta un

--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-3-835a19b5f6a9> in <module>() 
----> 1 mylist.remove(x) 

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

Che cosa sta succedendo?

risposta

4

Osservando il codice sorgente, list.remove utilizza la funzione PyObject_RichCompareBool per confrontare gli oggetti. Questa funzione contiene all'inizio:

/* Quick result when objects are the same. 
Guarantees that identity implies equality. */ 
if (v == w) { 
    if (op == Py_EQ) 
     return 1; 
    else if (op == Py_NE) 
     return 0; 
} 

Quindi confronta prima l'identità dell'oggetto. Solo se gli oggetti sono diversi, procede all'utilizzo dell'operatore ==.

Nell'esempio, se x è il primo oggetto nell'elenco, sarà lo stesso oggetto del valore rimosso e pertanto sarà considerato uguale dalla funzione sopra riportata e rimosso. Se qualcos'altro è il primo oggetto, verrà confrontato con con l'operatore ==, che restituirà un array numpy e causerà un errore in quanto non può essere convertito in un valore booleano.

I in opere operatore nello stesso modo, così x in [x,1] restituisce True mentre x in [1,x] genera un errore.

1

L'errore si verifica la seconda volta perché test 42 di identità con x fallisce e Python ricade confronto x con il numero intero 42 utilizzando uguaglianza (==).

mylist.remove(x) si libera della prima occorrenza del x nella lista senza alcun inconveniente perché x is x rendimenti True.Il problema è che quando il primo elemento del primo è 42, x is 42 restituisce False in modo che Python provi invece a x == 42.

Questo test di uguaglianza restituisce l'array array([False, False, False]). A differenza degli oggetti Python nativi, gli array NumPy hanno un ambiguo valore di verità e viene generato un errore.

Problemi correlati