Mam dużą ilość kodu Pythona, który próbuje obsługiwać liczby z dokładnością do czterech dziesiętnych i utknąłem z Pythona 2.4 z wielu powodów. Kod wykonuje bardzo uproszczoną matematykę (jest to kod zarządzania kredytem, który pobiera lub dodaje kredyty w większości).Zło w pytonie dziesiętnym/zmiennoprzecinkowe
Wymusił użycie float i Decimal (MySQLdb zwraca obiekty dziesiętne dla typów SQL DECIMAL). Po kilku dziwnych błędach pochodzących z użycia, znalazłem podstawową przyczynę wszystkich, aby być kilkoma miejscami w kodzie, które unoszą się i dziesiętne są porównywane.
mam do przypadków tak:
>>> from decimal import Decimal
>>> max(Decimal('0.06'), 0.6)
Decimal("0.06")
Teraz mój strach jest, że nie może być w stanie złapać wszystkie takie przypadki w kodzie. (normalny programista będzie robił x> 0 zamiast x> dziesiętny ("0.0000") i bardzo trudno jest go uniknąć)
Wymyśliłem łatkę (inspirowaną poprawkami do pakietu dziesiętnego w 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
po prostu zrobić to w bardzo wczesnym biblioteki ładowania i będzie to zmienić dziesiętną zachowanie pakietu, pozwalając na pływaka na dziesiętny konwersji przed porównaniem (aby uniknąć uderzenia domyślnego obiektu Pythona do obiektu porównanie).
W szczególności użyłem "str" zamiast "repr", ponieważ naprawia niektóre przypadki zaokrąglania floata. Na przykład.
>>> Decimal(str(0.6))
Decimal("0.6")
>>> Decimal(repr(0.6))
Decimal("0.59999999999999998")
Teraz moje pytanie brzmi: Am I brakuje czegoś tutaj? Czy to jest dość bezpieczne? czy coś tu łamie? (mam na myśli autorów pakietu miał bardzo silne powody, aby uniknąć pływaków tak dużo)
Wystarczy zauważyć, że "return NotImplemented" pochodzi z samego pakietu decimal.py. Dwie dodane przeze mnie linie znajdują się między komentarzami. Zgadzam się z twoim podejściem, jednak w tej implementacji pyton pozwala na logicznie szalone porównania między obiektami, które, jak zakładamy, są liczbami. Hmm, innym pomysłem może być podniesienie błędu zamiast niejawnej konwersji, ale niezależnie od tego, myślę, że muszę coś zrobić ... –
'return NotImplemented' jest poprawne i jest poprawne, [dokumentacja określona] (http: // docs .python.org/reference/datamodel.html # emulating-numeric-types) rzecz, którą należy zwrócić w przypadku nieobsługiwanego porównania. To pozwala pythonowi próbować znaleźć inny sposób robienia rzeczy. – aaronasterling
+1 za użycie terminu "łatanie małp", które doprowadziło mnie do wikipedii, aby stwierdzić, że pochodzi ona od "łatania partyzantów", jak w wojnie partyzanckiej =). – Tommy