Je suis tombé sur du code avec une ligne similaire à
x[x<2]=0
Jouant avec les variations, je suis toujours coincé sur ce que fait cette syntaxe.
Exemples:
>>> 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]
python
python-2.7
numpy
Aberger
la source
la source
TypeError: unorderable types: list() < int()
.Réponses:
Cela n'a de sens qu'avec les tableaux NumPy . Le comportement avec les listes est inutile, et spécifique à Python 2 (pas à Python 3). Vous voudrez peut-être vérifier si l'objet d'origine était bien un tableau NumPy (voir plus loin ci-dessous) et non une liste.
Mais dans votre code ici, x est une simple liste.
Depuis
x < 2
est faux c'est-à-dire 0, donc
x[x<2]
estx[0]
x[0]
se change.Inversement,
x[x>2]
estx[True]
oux[1]
Alors, ça
x[1]
change.Pourquoi cela arrive-t-il?
Les règles de comparaison sont:
Lorsque vous commandez deux chaînes ou deux types numériques, l'ordre est effectué de la manière attendue (ordre lexicographique pour chaîne, ordre numérique pour les entiers).
Lorsque vous commandez un type numérique et un type non numérique, le type numérique vient en premier.
Lorsque vous commandez deux types incompatibles où aucun n'est numérique, ils sont classés par ordre alphabétique de leurs noms de types:
Donc, nous avons l'ordre suivant
numérique <liste <chaîne <tuple
Voir la réponse acceptée pour Comment Python compare-t-il string et int? .
Si x est un tableau NumPy , la syntaxe a plus de sens en raison de l' indexation de tableau booléen . Dans ce cas, ce
x < 2
n'est pas du tout un booléen; c'est un tableau de booléens représentant si chaque élément dex
était inférieur à 2.x[x < 2] = 0
puis sélectionne les éléments dex
qui étaient inférieurs à 2 et définit ces cellules sur 0. Voir Indexation .>>> 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
la source
import
pour numpy.[0 if i < 2 else i for i in x]
,.) Ou est-ce que ce style est encouragé dans Numpy?x[x<2]
renverra un tableau numpy, tandis que[0 if i<2 else i for i in x]
renvoie une liste. Cela est dû au fait qu'ilx[x<2]
s'agit d'une opération d'indexation (appelée dans numpy / scipy / pandas une opération de découpage en raison de la possibilité de masquer les données), alors que la compréhension de la liste est une nouvelle définition d'objet. Voir l' indexation NumPy>>> x = [1,2,3,4,5] >>> x<2 False >>> x[False] 1 >>> x[True] 2
Le booléen est simplement converti en entier. L'index est 0 ou 1.
la source
x
et2
sont " ordonnés de manière cohérente mais arbitraire " et que l'ordre peut changer dans différentes implémentations Python.x<2 == false
?bool
n'est pas converti en un entier, abool
en Python est un entierbool
est une sous-classe deint
.Le code d'origine de votre question ne fonctionne qu'en Python 2. Si
x
est unlist
en Python 2, la comparaisonx < y
estFalse
siy
est unint
eger. En effet, il n’est pas logique de comparer une liste avec un entier. Cependant en Python 2, si les opérandes ne sont pas comparables, la comparaison est basée en CPython sur l' ordre alphabétique des noms des types ; en outre, tous les chiffres viennent en premier dans les comparaisons de type mixte . Cela n'est même pas précisé dans la documentation de CPython 2, et différentes implémentations de Python 2 pourraient donner des résultats différents. Cela[1, 2, 3, 4, 5] < 2
équivaut àFalse
parce que2
c'est un nombre et donc "plus petit" qu'unlist
dans CPython. Cette comparaison mitigée a finalement étéconsidérée comme une fonctionnalité trop obscure , et a été supprimée dans Python 3.0.Maintenant, le résultat de
<
est unbool
; etbool
est une sous - classe deint
:>>> isinstance(False, int) True >>> isinstance(True, int) True >>> False == 0 True >>> True == 1 True >>> False + 5 5 >>> True + 5 6
Donc, fondamentalement, vous prenez l'élément 0 ou 1 selon que la comparaison est vraie ou fausse.
Si vous essayez le code ci-dessus dans Python 3, vous obtiendrez en
TypeError: unorderable types: list() < int()
raison d' un changement dans Python 3.0 :Il existe de nombreux types de données qui surchargent les opérateurs de comparaison pour faire quelque chose de différent (dataframes de pandas, tableaux de numpy). Si le code que vous utilisiez faisait autre chose, c'était parce qu'il ne
x
s'agissait pas d'unlist
, mais d'une instance d'une autre classe avec un opérateur<
remplacé pour renvoyer une valeur qui n'est pas abool
; et cette valeur a ensuite été gérée spécialement parx[]
(aka__getitem__
/__setitem__
)la source
+False
Salut Perl, hey JavaScript, comment vas-tu?UNARY_POSITIVE
opcode qui appelle le__pos__
__setitem__
plutôt que__getitem__
dans votre dernière section. J'espère également que cela ne vous dérange pas que ma réponse ait été inspirée par cette partie de votre réponse.__getitem__
bien que tout aussi aurait pu être__setitem__
et__delitem__
Cela a une autre utilité: le code golf. Le code golf est l'art d'écrire des programmes qui résolvent certains problèmes en aussi peu d'octets de code source que possible.
return(a,b)[c<d]
équivaut à peu près à
if c < d: return b else: return a
sauf que a et b sont évalués dans la première version, mais pas dans la deuxième version.
c<d
évalue àTrue
ouFalse
.(a, b)
est un tuple.L'indexation sur un tuple fonctionne comme l'indexation sur une liste:
(3,5)[1]
==5
.True
est égal à1
etFalse
est égal à0
.(a,b)[c<d]
(a,b)[True]
(a,b)[1]
b
ou pour
False
:(a,b)[c<d]
(a,b)[False]
(a,b)[0]
a
Il existe une bonne liste sur le réseau d'échange de piles de nombreuses choses désagréables que vous pouvez faire à python afin d'économiser quelques octets. /codegolf/54/tips-for-golfing-in-python
Bien que dans le code normal, cela ne devrait jamais être utilisé, et dans votre cas, cela signifierait qu'il
x
agit à la fois comme quelque chose qui peut être comparé à un entier et comme un conteneur qui prend en charge le découpage, ce qui est une combinaison très inhabituelle. C'est probablement du code Numpy, comme d'autres l'ont souligné.la source
Code Golf is the art of writing programs
: ')En général, cela peut vouloir dire n'importe quoi . Il était déjà expliqué ce qu'il signifie que si
x
est unlist
ounumpy.ndarray
mais en général , il ne dépend que de la façon dont les opérateurs de comparaison (<
,>
...) et aussi comment le get / set-point ([...]
-syntax) sont mis en œuvre.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!
Car:
x < value
est équivalent àx.__lt__(value)
x[value]
équivaut (à peu près) àx.__getitem__(value)
x[value] = othervalue
est (également à peu près) équivalent àx.__setitem__(value, othervalue)
.Cela peut être personnalisé pour faire tout ce que vous voulez. Juste à titre d'exemple (imite un peu l'indexation numpys-booléenne):
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
Voyons maintenant ce qui se passe si vous l'utilisez:
>>> 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])
Notez que ce n'est qu'une possibilité. Vous êtes libre de mettre en œuvre presque tout ce que vous voulez.
la source