Mi sono imbattuto in un codice con una riga simile a
x[x<2]=0
Giocando con le variazioni, sono ancora bloccato su ciò che fa questa sintassi.
Esempi:
>>> x = [1,2,3,4,5]
>>> x[x<2]
1
>>> x[x<3]
1
>>> x[x>2]
2
>>> x[x<2]=0
>>> x
[0, 2, 3, 4, 5]
Mi sono imbattuto in un codice con una riga simile a
x[x<2]=0
Giocando con le variazioni, sono ancora bloccato su ciò che fa questa sintassi.
Esempi:
>>> x = [1,2,3,4,5]
>>> x[x<2]
1
>>> x[x<3]
1
>>> x[x>2]
2
>>> x[x<2]=0
>>> x
[0, 2, 3, 4, 5]
TypeError: unorderable types: list() < int().
Risposte:
Questo ha senso solo con gli array NumPy . Il comportamento con le liste è inutile e specifico per Python 2 (non Python 3). Potresti voler ricontrollare se l'oggetto originale era effettivamente un array NumPy (vedi più avanti) e non un elenco.
Ma nel tuo codice qui, x è un semplice elenco.
Da
x < 2
è False cioè 0, quindi
x[x<2] è x[0]
x[0] viene cambiato.
Al contrario, x[x>2]è x[True]ox[1]
Quindi, x[1]viene cambiato.
Perché succede questo?
Le regole per il confronto sono:
Quando si ordinano due stringhe o due tipi numerici, l'ordinamento viene eseguito nel modo previsto (ordinamento lessicografico per stringa, ordinamento numerico per interi).
Quando ordini un tipo numerico e uno non numerico, il tipo numerico viene prima.
Quando si ordinano due tipi incompatibili, dove nessuno dei due è numerico, vengono ordinati in base all'ordine alfabetico dei nomi dei tipi:
Quindi, abbiamo il seguente ordine
numeric <list <string <tuple
Vedi la risposta accettata per Come fa Python a confrontare string e int? .
Se x è un array NumPy , la sintassi ha più senso a causa dell'indicizzazione dell'array booleano . In tal caso, x < 2non è affatto un booleano; è un array di valori booleani che rappresentano se ogni elemento di xera minore di 2. x[x < 2] = 0quindi seleziona gli elementi di xche erano minori di 2 e imposta quelle celle a 0. Vedi Indicizzazione .
>>> x = np.array([1., -1., -2., 3])
>>> x < 0
array([False, True, True, False], dtype=bool)
>>> x[x < 0] += 20 # All elements < 0 get increased by 20
>>> x
array([ 1., 19., 18., 3.]) # Only elements < 0 are affected
importper numpy.
[0 if i < 2 else i for i in x],.) O questo stile è incoraggiato in Numpy?
x[x<2]restituirà un array numpy, mentre [0 if i<2 else i for i in x]restituirà un elenco. Questo perché x[x<2]è un'operazione di indicizzazione (indicata in numpy / scipy / pandas come operazione di affettamento a causa della capacità di mascherare i dati), mentre la comprensione dell'elenco è una nuova definizione di oggetto. Vedi l' indicizzazione NumPy
>>> x = [1,2,3,4,5]
>>> x<2
False
>>> x[False]
1
>>> x[True]
2
Il valore bool viene semplicemente convertito in un numero intero. L'indice è 0 o 1.
xe 2sono " ordinati in modo coerente ma arbitrario " e che l'ordine potrebbe cambiare in diverse implementazioni di Python.
x<2 == false?
boolnon viene convertito in un numero intero, un boolin Python è un numero intero
bool è una sottoclasse di int.
Il codice originale nella tua domanda funziona solo in Python 2. Se xè a listin Python 2, il confronto x < yè Falsese yè un integer. Questo perché non ha senso confrontare un elenco con un numero intero. Tuttavia in Python 2, se gli operandi non sono confrontabili, il confronto si basa in CPython sull'ordinamento alfabetico dei nomi dei tipi ; inoltre, tutti i numeri vengono prima nei confronti di tipo misto . Questo non è nemmeno spiegato nella documentazione di CPython 2 e diverse implementazioni di Python 2 potrebbero dare risultati diversi. Vale [1, 2, 3, 4, 5] < 2a Falseperché 2è un numero e quindi "più piccolo" di a listin CPython. Alla fine questo confronto misto è statoritenuta una funzionalità troppo oscura ed è stata rimossa in Python 3.0.
Ora, il risultato di <è a bool; ed boolè una sottoclasse diint :
>>> isinstance(False, int)
True
>>> isinstance(True, int)
True
>>> False == 0
True
>>> True == 1
True
>>> False + 5
5
>>> True + 5
6
Quindi in pratica stai prendendo l'elemento 0 o 1 a seconda che il confronto sia vero o falso.
Se provi il codice sopra in Python 3, otterrai a TypeError: unorderable types: list() < int()causa di una modifica in Python 3.0 :
Ordinazione di confronti
Python 3.0 ha semplificato le regole per ordinare i confronti:
Gli operatori di confronto ordinamento (
<,<=,>=,>) sollevare unTypeErroreccezione quando gli operandi non hanno un ordinamento naturale significativo. Pertanto, espressioni come1 < '',0 > Noneolen <= lennon sono più valide, e ad esempioNone < NonesollevaTypeErrorinvece di restituireFalse. Un corollario è che l'ordinamento di un elenco eterogeneo non ha più senso: tutti gli elementi devono essere confrontabili tra loro. Si noti che questo non si applica agli operatori==e!=: oggetti di diversi tipi incomparabili vengono sempre confrontati in modo diverso tra loro.
Ci sono molti tipi di dati che sovraccaricano gli operatori di confronto per fare qualcosa di diverso (dataframe dai panda, array di numpy). Se il codice che stavi usando faceva qualcos'altro, era perché nonx era alist , ma un'istanza di qualche altra classe con l'operatore <sovrascritto per restituire un valore che non è a bool; e questo valore è stato quindi gestito appositamente da x[](aka __getitem__/ __setitem__)
+FalseCiao Perl, ehi JavaScript, come va?
UNARY_POSITIVEcodice operativo che chiama__pos__
__setitem__invece che __getitem__nella tua ultima sezione. Inoltre spero che non ti dispiaccia che la mia risposta sia stata ispirata da quella parte della tua risposta.
__getitem__anche se ugualmente avrebbe potuto essere __setitem__e__delitem__
Questo ha un altro uso: il golf di codice. Il code golf è l'arte di scrivere programmi che risolvono alcuni problemi con il minor numero possibile di byte di codice sorgente.
return(a,b)[c<d]
è più o meno equivalente a
if c < d:
return b
else:
return a
tranne che sia a che b sono valutati nella prima versione, ma non nella seconda versione.
c<drestituisce Trueo False.
(a, b)è una tupla.
L'indicizzazione su una tupla funziona come l'indicizzazione su una lista: (3,5)[1]== 5.
Trueè uguale a 1ed Falseè uguale a 0.
(a,b)[c<d](a,b)[True](a,b)[1]bo per False:
(a,b)[c<d](a,b)[False](a,b)[0]aC'è un buon elenco sulla rete di scambio di stack di molte cose brutte che puoi fare a Python per salvare alcuni byte. /codegolf/54/tips-for-golfing-in-python
Sebbene nel codice normale questo non dovrebbe mai essere usato, e nel tuo caso significherebbe che xagisce sia come qualcosa che può essere paragonato a un numero intero che come un contenitore che supporta lo slicing, che è una combinazione molto insolita. Probabilmente è codice Numpy, come altri hanno sottolineato.
Code Golf is the art of writing programs: ')
In generale potrebbe significare qualsiasi cosa . E 'stato già spiegato che cosa significa se xè un listo numpy.ndarray, ma, in generale, dipende solo da come gli operatori di confronto ( <, >, ...) e anche come il get / set-item ( [...]sono implementati -syntax).
x.__getitem__(x.__lt__(2)) # this is what x[x < 2] means!
x.__setitem__(x.__lt__(2), 0) # this is what x[x < 2] = 0 means!
Perché:
x < value è equivalente a x.__lt__(value)x[value] è (approssimativamente) equivalente a x.__getitem__(value) x[value] = othervalueè (anche approssimativamente) equivalente a x.__setitem__(value, othervalue).Questo può essere personalizzato per fare tutto ciò che desideri. Proprio come un esempio (imita un po 'di indicizzazione numpys-booleana):
class Test:
def __init__(self, value):
self.value = value
def __lt__(self, other):
# You could do anything in here. For example create a new list indicating if that
# element is less than the other value
res = [item < other for item in self.value]
return self.__class__(res)
def __repr__(self):
return '{0} ({1})'.format(self.__class__.__name__, self.value)
def __getitem__(self, item):
# If you index with an instance of this class use "boolean-indexing"
if isinstance(item, Test):
res = self.__class__([i for i, index in zip(self.value, item) if index])
return res
# Something else was given just try to use it on the value
return self.value[item]
def __setitem__(self, item, value):
if isinstance(item, Test):
self.value = [i if not index else value for i, index in zip(self.value, item)]
else:
self.value[item] = value
Quindi ora vediamo cosa succede se lo usi:
>>> a = Test([1,2,3])
>>> a
Test ([1, 2, 3])
>>> a < 2 # calls __lt__
Test ([True, False, False])
>>> a[Test([True, False, False])] # calls __getitem__
Test ([1])
>>> a[a < 2] # or short form
Test ([1])
>>> a[a < 2] = 0 # calls __setitem__
>>> a
Test ([0, 2, 3])
Notare che questa è solo una possibilità. Sei libero di implementare quasi tutto ciò che desideri.