86 votes

Que signifie x [x < 2] = 0 signifie en Python ?

Je suis tombé sur un code avec une ligne similaire à

Jouer avec des variations, je suis encore coincé sur ce qui fait de cette syntaxe.

Exemples :

121voto

trans1st0r Points 1603

Cela n'a de sens avec NumPy tableaux. Le comportement avec des listes est inutile, et spécifique à Python 2 (pas de Python 3). Vous pouvez double-vérifier si l'objet initial était en effet un tableau NumPy (voir ci-dessous) et non sur une liste.

Mais dans ton code ici, x est une simple liste.

Depuis

x < 2

est Faux j'.e 0, donc

x[x<2] est x[0]

x[0] est changé.

À l'inverse, x[x>2] est x[True] ou x[1]

Donc, x[1] est changé.

Pourquoi est-ce arrivé?

Les règles à des fins de comparaison sont les suivants:

  1. Lorsque vous commandez deux chaînes ou deux types numériques de la commande se fait en la manière prévue (lexicographique de commande pour la chaîne numérique de la commande pour les entiers).

  2. Lorsque vous commandez un code numérique et non-numérique de type, le type numérique vient en premier.

  3. Lorsque vous commandez deux types incompatibles où ni est numérique, ils sont classés par l'ordre alphabétique de leur typenames:

Donc, nous avons l'ordre suivant

numérique < list < string < tuple

Voir la accepté de répondre pour Comment Python comparer string et int?.

Si x est un tableau NumPy, la syntaxe a plus de sens en raison de booléen tableau d'indexation. Dans ce cas, x < 2 n'est pas un booléen à tous; c'est un tableau de booléens indiquant si chaque élément de l' x a moins de 2. x[x < 2] = 0 puis sélectionne les éléments d' x qui ont moins de 2 et jeux de ces cellules à 0. Voir L'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

45voto

Karoly Horvath Points 45145
<pre><code></code><p>Le bool est simplement converti en un entier. L’index est 0 ou 1.</p></pre>

14voto

Antti Haapala Points 11542

Le code d'origine dans votre question ne fonctionne qu'en Python 2. Si x est list en Python 2, la comparaison x < y est False si y est integer. C'est parce qu'il ne fait pas de sens de comparer une liste avec un nombre entier. Cependant en Python 2, si les opérandes ne sont pas comparables, la comparaison est basée dans Disponible sur l' ordre alphabétique des noms des types; en outre tous les numéros de la première place de mixte-type de comparaisons. Ce n'est même pas précisé dans la documentation de Disponible 2, et les différentes implémentations de Python 2 pourrait donner des résultats différents. C'est - [1, 2, 3, 4, 5] < 2 évalue False car 2 est un nombre, et donc plus "petit" qu'un list dans Disponible. Ce mixte de comparaison a finalement été jugée trop obscur d'une fonction, et a été supprimée en Python 3.0.


Maintenant, le résultat de l' < est bool; bool est une sous-classe de int:

>>> 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 en Python 3, vous obtiendrez TypeError: unorderable types: list() < int() en raison d' un changement de Python 3.0:

La Commande De Comparaisons

Python 3.0 a simplifié les règles de classement des comparaisons:

La commande des opérateurs de comparaison (<, <=, >=, >) posent un TypeError exception lorsque les opérandes ne pas avoir un sens naturel de la commande. Ainsi, des expressions comme 1 < '', 0 > None ou len <= len "ne sont plus valables, et, par exemple, None < None soulève TypeError au lieu de renvoyer False. Un corollaire est que le tri d'un ensemble hétérogène de la liste n'a plus de sens – tous les éléments doivent être comparables les uns aux autres. Notez que ceci ne s'applique pas à l' == et != opérateurs: les objets de différents incomparable types de comparer toujours inégaux les uns aux autres.


Il existe de nombreux types de données qui surcharge les opérateurs de comparaison à faire quelque chose de différent (dataframes de pandas, numpy de tableaux). Si le code que vous utilisiez fait autre chose, c'était parce qu' x était pas un list, mais une instance d'une autre classe avec l'opérateur < substituée pour renvoyer une valeur qui n'est pas un bool; et cette valeur a ensuite été traitées spécialement en x[] (aka __getitem__/__setitem__)

9voto

Filip Haglund Points 985

Cela a une autre utilité: code de golf. Code de golf est l'art de l'écriture de programmes qui permettent de résoudre un certain problème en aussi peu de code source octets que possible.

return(a,b)[c<d]

est à peu près équivalent

if c < d:
    return b
else:
    return a

sauf que a et b sont évaluées dans la première version, mais pas dans la deuxième version.

c<d évalue True ou False.
(a, b) est un n-uplet.
L'indexation sur un n-uplet de travaux tels que l'indexation sur une liste: (3,5)[1] == 5.
True est égal à 1 et False est égal à 0.

  1. (a,b)[c<d]
  2. (a,b)[True]
  3. (a,b)[1]
  4. b

ou pour False:

  1. (a,b)[c<d]
  2. (a,b)[False]
  3. (a,b)[0]
  4. a

Il y a une bonne liste sur la pile réseau d'échange de beaucoup de vilaines choses que vous pouvez faire pour python afin d'économiser quelques octets. https://codegolf.stackexchange.com/questions/54/tips-for-golfing-in-python

Bien que dans le code, ce ne doit jamais être utilisé, et dans votre cas, cela signifierait que 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 un très étrange combinaison. C'est probablement Numpy code, comme d'autres l'ont souligné.

6voto

MSeifert Points 6307

En général cela pourrait signifier quelque chose. Il a été déjà expliqué ce que cela signifie si x est list ou numpy.ndarray , mais en général, il ne dépend que de la façon dont les opérateurs de comparaison (<, >, ...) et aussi comment les get/set-point ([...]-syntaxe) 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!

Parce que:

  • x < value est équivalent à x.__lt__(value)
  • x[value] est de (environ) équivalent à x.__getitem__(value)
  • x[value] = othervalue est (environ) équivalent à x.__setitem__(value, othervalue).

Ce qui peut être personnalisé pour faire tout ce que vous voulez. Juste à titre d'exemple (imite un peu numpys-boolean indexation):

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

Maintenant, nous allons voir 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])

À noter que c'est juste une possibilité. Vous êtes libre de mettre presque tout ce que vous voulez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X