PYTHON, WHY U NO HAZ A SIGN FUNCTION ?


Bien que Python soit un langage massivement utilisé par la communauté scientifique, la lib standard ne contient pas de fonction aussi simple que sign(). Et on voit ça et là des libs qui contiennent quelque chose comme ça:

def sign(x):
    if x > 0:
        return 1
    if x == 0:
        return 0
    return -1
 
>>> sign(3)
1
>>> sign(-3)
-1
>>> sign(0)
0

Comme d’autres de choix étonnants dans l’architecture de Python, il y a une raison raisonnablement raisonnable : il n’existe aucun standard sur ce que doit faire une telle fonction dans les cas ambigües.

En effet, que doit faire la fonction avec NaN ? Avec un complexe ?

Il y a eu un débat sur ce qu’il faut faire dans ce cas, et un consensus n’a PAS été trouvé.

Par contre, il existe un standard international définissant une autre opération : celle de copier un signe. Elle a donc été implémentée :

>>> from math import copysign
>>> copysign(10, -3)
-10.0
>>> copysign(10, 22)
10.0
>>> copysign(10, float('-NaN'))
-10
>>> copysign(10, -2j)
Traceback (most recent call last):
  File "<ipython-input-13-ece93d1317dc>", line 1, in <module>
    copysign(10, -2j)
TypeError: can't convert complex to float

Copier le signe n’est pas la même chose que de retourner quelque chose selon le signe, et donc sémantiquement, choisir quoi retourner était plus facile. Comme la plupart du temps, on veut récupérer -1 ou 1 pour le multiplier avec quelque chose et justement copier le signe, cela résolvait pas mal de problèmes.

Mais même dans le rare cas où on a besoin du résultat que renverrait sign(), il est très facile à obtenir en une ligne :

>>> mon_nombre = 3
>>> mon_nombre and copysign(1, mon_nombre)
1.0
>>> mon_nombre = -3
>>> mon_nombre and copysign(1, mon_nombre)
-1.0
>>> mon_nombre = 0
>>> mon_nombre and copysign(1, mon_nombre)
0

Et pour ce cas de figure, les retours sur des valeurs ambigües sont laissés à la charge du codeur.

P.S: je sais qu’il y a des exemples sur le net montrant cmp(0, mon_nombre) pour obtenir la même fonctionnalité. Sachez que cmp a été retirée de Python 3, donc faites attention si vous l’utilisez.

9 thoughts on “PYTHON, WHY U NO HAZ A SIGN FUNCTION ?

  • entwanne

    Quitte à créer soi-même une fonction avec un `and`, je préfère un

    def sign(x)
      return x and (-1, 1)[x > 0]

    qui est plus lisible je trouve qu’une fonction `copysign` dont le comportement peut sembler flou au premier abord.

    • Sam Post author

      @entwanne: et ça sera probablement plus rapide à l’éxécution en plus, puisqu’il y a une appel en moins. Copysign reste néanmoins idéal pour le cas le plus courant où on souhaite faire la multiplication derrière.

  • cym13

    @entwanne: Jolie structure, très astucieuse j’aime beaucoup ! Je la garde sous le coude même si elle ne présente pas l’avantage de pouvoir prendre des nombres complexes comme copysign.

  • Pyo

    Coucou,
    À quoi sert le “x and” alors??


    def sign(x):
    return (-1,1)[x>0]

  • poulpe

    return x / abs(x or 1)
    Surement un poil plus lent que la méthode à entwanne, mais plus rapide que celle de Sam :)

  • kontre

    Les scientifiques, comme très souvent, utilisent numpy :

    import numpy as np
    np.sign(-1)  # -1
    np.sign(0)  # 0
    np.sign(1)  # 1
    np.sign(nan)  # nan
    np.sign(1j)  # (1+0j)
    np.sign(-1+1j)  # (-1+0j)
    np.sign(-1j)  # (-1+0j)

    Ne me demandez pas la logique pour les complexes, la doc n’en parle pas : http://docs.scipy.org/doc/numpy/reference/generated/numpy.sign.html

  • Sam Post author

    @poulpe : pas mal, ça évite malicieusement la division par zéro.

Comments are closed.

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.