Python 金钱类
项目描述
具有可选 CLDR 支持的区域设置感知格式和可扩展货币兑换解决方案的货币类。
这是版本 1.3.0。
此包兼容 Python 2.7、3.4、3.5(在 2.7.11、3.4.4、3.5.1 中测试),但Python 版本之间存在重要差异。所有代码示例都使用 Python 3.x。
内容
<nav class="contents local" id="contents" role="doc-toc"> </nav>安装
安装最新版本:
pip install money
对于区域感知格式,还要安装最新版本的Babel(需要 2.2 或更高版本):
pip install babel
用法
>>> from money import Money
>>> m = Money(amount='2.22', currency='EUR')
>>> m
EUR 2.22
金额可以是十进制中的任何有效值。十进制(值)和货币应该是三个字母的货币代码。Money 对象按照惯例是不可变的并且是可散列的。创建后,您可以使用只读属性amount (decimal.Decimal) 和currency (str) 来访问其内部组件:
>>> m = Money(2, 'USD')
>>> m.amount
Decimal('2')
>>> m.currency
'USD'
Money 模拟数字类型,您可以在货币对象之间应用大多数算术和比较运算符,以及整数 (int) 和十进制数 (decimal.Decimal) 的加法、减法和除法:
>>> m = Money('2.22', 'EUR')
>>> m / 2
EUR 1.11
>>> m + Money('7.77', 'EUR')
EUR 9.99
更正式地说,AAA和BBB是不同的货币:
操作员 |
钱AAA |
钱 BBB |
整数,十进制 |
|
---|---|---|---|---|
钱AAA |
+ , - |
钱 |
不适用 |
钱 |
* |
不适用 |
不适用 |
钱 |
|
/ , // |
十进制 |
不适用 |
钱 |
|
> , >= < , <= |
比较金额。 |
不适用 |
不适用 |
|
== |
错误的 |
错误的 |
不直接支持带有浮点数的算术运算。如果需要对浮点数进行操作,则必须先将浮点数转换为Decimal,或者将Money 对象转换为浮点数(即float(m))。请注意浮点运算的问题和限制。
货币预设
如果您在代码中使用固定货币,您可能会发现创建货币预设的 Money 子类很方便:
class EUR(Money):
def __init__(self, amount='0'):
super().__init__(amount=amount, currency='EUR')
price = EUR('9.99')
格式化
Money 对象默认使用 en_US 格式和货币代码打印。
>>> m = Money('1234.567', 'EUR')
>>> str(m)
'EUR 1,234.57'
使用format(locale=LC_NUMERIC, pattern=None, currency_digits=True, format_type='standard')进行带货币扩展的区域感知格式化。format()依赖于babel.numbers.format_currency(),并且需要安装 Babel 2.2 或更高版本。
>>> m = Money('1234.567', 'USD')
>>> m.format('en_US')
'$1,234.57'
>>> m.format('es_ES')
'1.234,57\xa0$'
字符\xa0是一个 unicode 不间断空格。如果没有传递语言环境,Babel 将使用您系统的语言环境。您还可以为 format() 提供特定模式:
>>> m = Money('-1234.567', 'USD')
>>> # Regular US format:
>>> m.format('en_US', '¤#,##0.00')
'-$1,234.57'
>>> # Custom negative format:
>>> m.format('en_US', '¤#,##0.00;<¤#,##0.00>')
'<$1,234.57>'
>>> # Spanish format, full currency name:
>>> m.format('es_ES', '#,##0.00 ¤¤¤')
'-1.234,57 dólares estadounidenses'
>>> # Same as above, but rounding (overriding currency natural format):
>>> m.format('es_ES', '#0 ¤¤¤', currency_digits=False)
'-1235 dólares estadounidenses'
有关格式化的更多详细信息,请参阅Babel docs on currency formatting。要了解有关格式化模式语法的更多信息,请查看Unicode TR35。
货币兑换
货币兑换通过“安装”实现抽象基类 ( abc ) money.exchange.BackendBase的后端类来工作。它的 API 通过money.xrates以及设置函数xrates.install(pythonpath)、xrates.uninstall()和xrates.backend_name 公开。
包括一个简单的概念验证后端money.exchange.SimpleBackend:
from decimal import Decimal
from money import Money, xrates
xrates.install('money.exchange.SimpleBackend')
xrates.base = 'USD'
xrates.setrate('AAA', Decimal('2'))
xrates.setrate('BBB', Decimal('8'))
a = Money(1, 'AAA')
b = Money(1, 'BBB')
assert a.to('BBB') == Money('4', 'BBB')
assert b.to('AAA') == Money('0.25', 'AAA')
assert a + b.to('AAA') == Money('1.25', 'AAA')
XMoney
您可以使用money.XMoney(Money 的子类),在加、减、除货币对象(+、+=、-、-=、/、//)时进行自动货币转换。这在聚合大量具有异构货币的货币对象时很有用。最左边对象的货币具有优先权。
from money import XMoney
# Register backend and rates as above...
a = XMoney(1, 'AAA')
b = XMoney(1, 'BBB')
assert sum([a, b]) == XMoney('1.25', 'AAA')
例外
在money.exceptions中找到。
- 金钱异常(异常)
所有异常的基类。
- 货币不匹配(MoneyException,ValueError)
混合不同货币时抛出,例如Money(2, 'EUR') + Money(2, 'USD')。Money 对象必须首先转换为相同的货币,或者可以使用 XMoney 进行自动转换。
- InvalidOperandType(MoneyException,TypeError)
尝试无效操作时抛出,例如货币对象之间的乘法。
- ExchangeError(MoneyException)
交换异常的基类。
- ExchangeBackendNotInstalled(ExchangeError)
如果尝试转换,但没有可用的后端,则抛出此异常。
- ExchangeRateNotFound(ExchangeError)
安装的后端未能在原始货币和目标货币之间提供合适的汇率。
等级制度
- 金钱异常
货币错配
无效操作数类型
- 交换错误
ExchangeBackendNotInstalled
ExchangeRateNotFound
Python版本之间的差异
表达 |
Python 2.x |
Python 3.x |
---|---|---|
轮(钱('2.5', 'EUR')) |
返回3.0,一个从零取整的浮点数。 |
返回EUR 2,这是一个金额四舍五入到最接近偶数的Money 对象。 |
Money('0', 'EUR').amount < '0' |
返回True。这是 Python 2.x 在比较 Decimal 对象与非数字对象时奇怪但预期的行为(注意 '0' 是一个字符串)。请参阅文档中的注释。 |
TypeError:不可排序的类型:decimal.Decimal() > str() |
设计决策
货币中有几个设计决策与当前可用的货币类实现不同:
本土化
不要在此包中保留任何类型的语言环境约定数据库。语言环境约定广泛且随时间而变化;跟踪它们本身就是一个项目。已经有这样一个项目和数据库(Unicode Common Locale Data Repository),以及一个优秀的 Python API:Babel。
货币
不需要货币类别。货币完全由其 ISO 4217 代码标识,并且由于其不断变化的性质,本地化或汇率数据预计将作为数据库/服务集中。
还:
模运算符 (%):不要覆盖以表示“百分比”。
数字类型:您可以在二进制操作中混合数字和货币,如果数量为零,对象的计算结果为 False。
全球默认货币:子类化是一种更安全的解决方案。
贡献
欢迎投稿。您可以使用常规的 github 机制。
为了向前兼容,并考虑到包的小尺寸,Python 2.7 在src-py2的不同源“分支”中得到支持。
要测试您的更改,您将需要tox和 python 2.7、3.4 和 3.5。只需 cd 到包根目录(通过 setup.py)并运行tox。
执照
money 是根据MIT 许可证发布的,可以在文件LICENSE中找到。