Advertisement
Guest User

Untitled

a guest
Feb 14th, 2016
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.89 KB | None | 0 0
  1. import decimal
  2. from functools import total_ordering
  3. from numbers import Real
  4.  
  5. class Context(object):
  6. def __init__(self, **kwargs):
  7. self.context = decimal.Context(**kwargs)
  8.  
  9. def __enter__(self):
  10. with decimal.localcontext(self.context) as c:
  11. return c
  12.  
  13. def __exit__(self, *args):
  14. pass
  15.  
  16. MONEY_CONTEXT = Context(prec=3, rounding=decimal.ROUND_HALF_UP)
  17.  
  18. @total_ordering
  19. class Money(object):
  20. def __init__(self, symbol, amount):
  21. self.symbol = symbol
  22. self.amount = amount
  23.  
  24. @classmethod
  25. def fromstr(cls, money):
  26. symbol, amount = money[0], money[1:]
  27. return cls(
  28. symbol,
  29. decimal.Decimal(amount).quantize(
  30. decimal.Decimal('.01'),
  31. rounding=decimal.ROUND_DOWN
  32. )
  33. )
  34.  
  35. def _raise_if_separate_types(self, other):
  36. if not isinstance(other, Money):
  37. raise TypeError("Can't use money and non-money together")
  38.  
  39. if not self.symbol == other.symbol:
  40. # not true, but conversions are another matter
  41. raise TypeError("Can't compare across monetary types")
  42.  
  43. def __eq__(self, other):
  44. self._raise_if_separate_types(other)
  45. return self.amount == other.amount
  46.  
  47. def __lt__(self, other):
  48. self._raise_if_separate_types(other)
  49. return self.amount < other.amount
  50.  
  51. def __add__(self, other):
  52. self._raise_if_separate_types(other)
  53.  
  54. with decimal.localcontext(_MONEY_CONTEXT):
  55. amount = self.amount + other.amount
  56.  
  57. return self.__class__(self.symbol, amount)
  58.  
  59. def __neg__(self):
  60. amount = (-self.amount)
  61. return self.__class__(self.symbol, amount)
  62.  
  63. def __sub__(self, other):
  64. self._raise_if_separate_types(other)
  65. return self + (-other)
  66.  
  67. def __mul__(self, other):
  68. if not isinstance(other, Real):
  69. raise TypeError("Can only multiple money by real numbers")
  70.  
  71. if isinstance(other, float):
  72. other = _MONEY_CONTEXT.create_decimal_from_float(other)
  73.  
  74. with MONEY_CONTEXT:
  75. amount = (self.amount * other).quantize(decimal.Decimal('.01'))
  76.  
  77. return self.__class__(self.symbol, amount)
  78.  
  79. def __div__(self, other):
  80. if not isinstance(other, Real):
  81. raise TypeError("Can only divide money by real numbers")
  82.  
  83. if isinstance(other, float):
  84. other = _MONEY_CONTEXT.create_decimal_from_float(other)
  85.  
  86. with MONEY_CONTEXT:
  87. amount = (self.amount / other).quantize(decimal.Decimal('.01'))
  88.  
  89. return self.__class__(self.symbol, amount)
  90.  
  91. def __str__(self):
  92. return '{}{!s}'.format(self.symbol, self.amount)
  93.  
  94. def __repr__(self):
  95. return 'Money(symbol={!r}, amount={!r})'.format(self.symbol, self.amount)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement