Question

J'ai une grande quantité de code python qui tente de gérer des nombres avec 4 précision décimale et je suis coincé avec Python 2.4 pour de nombreuses raisons. Le code fait mathématique très simpliste (son code de gestion de crédit qui prend ou ajouter des crédits pour la plupart)

Il a l'usage entremêlés de flotteur et décimal (MySQLdb retourne des objets décimal pour les types SQL DECIMAL). Après plusieurs bugs étranges à venir de l'utilisation, j'ai trouvé la cause racine de tout être quelques endroits dans le code qui flottent et sont comparés Décimales.

Je suis arrivé à des cas comme celui-ci:

>>> from decimal import Decimal
>>> max(Decimal('0.06'), 0.6)
Decimal("0.06")

Maintenant, je crains que je ne pourrais pas être en mesure d'attraper tous les cas dans le code. (Un programmeur normal continuer à faire x> 0 au lieu de x> décimal ( « 0,0000 ») et il est très difficile d'éviter)

Je suis venu avec un patch (inspiré par des améliorations à paquet décimal en python 2.7).

import decimal
def _convert_other(other):
     """Convert other to Decimal.

     Verifies that it's ok to use in an implicit construction.
     """
     if isinstance(other, Decimal):
         return other
     if isinstance(other, (int, long)):
         return Decimal(other)
     # Our small patch begins
     if isinstance(other, float):
         return Decimal(str(other))
     # Our small patch ends
     return NotImplemented
decimal._convert_other = _convert_other

Je fais juste dans une bibliothèque de chargement très tôt et il va changer le comportement du package décimal en permettant float à la conversion décimal avant des comparaisons (pour éviter de heurter l'objet par défaut de python à la comparaison d'objets).

I spécifiquement utilisé « str » au lieu de « rééd » car il fixe certains des cas d'arrondi de flotteur. Par exemple.

>>> Decimal(str(0.6))
Decimal("0.6")
>>> Decimal(repr(0.6))
Decimal("0.59999999999999998")

Maintenant, ma question est: Est-ce que je manque quelque chose ici? Est-ce assez sûr? ou suis-je cassais quelque chose ici? (Je pense aux auteurs du paquet avait des raisons très fortes à éviter flotteurs tellement)

Était-ce utile?

La solution

Je pense que vous voulez raise NotImplementedError() au lieu de return NotImplemented, pour commencer.

Ce que vous faites est appelé « patching singe », et il est correct de faire, tant que vous savez ce que vous faites, êtes au courant des retombées, et bien marcher que les retombées. En général, vous limiter à la fixation d'un bug ou d'un autre changement où vous savez que vous êtes altération du comportement est toujours correct et rétrocompatible.

Dans ce cas, parce que vous êtes patcher une classe, vous pouvez modifier le comportement en dehors des cas où vous l'utilisez. Si une autre utilise la bibliothèque décimale et repose en quelque sorte sur le comportement par défaut, il peut causer des bugs subtils. Le problème est que vous ne savez pas vraiment à moins que vous vérification tous votre code, y compris les dépendances, et de trouver tous les sites d'appel.

En fait - le faire à vos propres risques

.

Personnellement, je trouve plus rassurant de fixer tout mon code, ajouter des tests, et de le rendre plus difficile à faire la mauvaise chose (par exemple, l'utilisation wrapper des classes ou des fonctions d'assistance). Une autre approche serait d'instrument de votre code avec votre patch pour trouver tous les sites d'appel, puis revenir en arrière et de les corriger.

Edit - Je suppose que je dois ajouter que la raison probable qu'ils évitaient flotteurs est flotteurs ne peuvent pas représenter avec précision tous les numéros, ce qui est important si vous avez affaire avec de l'argent

.

Autres conseils

Il y a de très bonnes raisons d'éviter des flotteurs. Avec flotteurs, vous ne pouvez pas faire de manière fiable des comparaisons telles que ==,>,

Utilisation str () peut travailler pour vous si vous ne faites pas que beaucoup de calculs à virgule flottante, mais si vous faites beaucoup de calculs, le bruit de virgule flottante finira par être assez grand pour que str () vous donnera le mauvais réponse.

En somme, si (1) vous ne faites pas que beaucoup de calculs à virgule flottante, ou (2) vous n'avez pas besoin de faire des comparaisons comme ==,>,

Si vous voulez être sûr, puis retirez tout le code à virgule flottante.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top