Python中做会计的最佳实践
我正在写一个web2py的应用程序,需要对美元金额进行求和,而且不能丢失精度。我意识到我需要使用小数(Decimals)来处理这个问题,但我发现每次从数据库获取数字时,都得用:
Decimal(str(myval))
把它包裹起来。在我快要崩溃之前,难道没有更好的方法吗?我刚接触Python,所以很可能我忽略了一些明显的东西。
编辑:我的数据库是MS SQL Server,我把金额存储在SQL Server的money
字段中(我相信这个实现类似于小数,也就是整数运算,而不是浮点运算)。
我通过web2py框架连接到数据库(这个框架使用pyodbc
来连接SQL Server)。我相信web2py对小数类型有一些支持。例如,我的web2py字段定义看起来像这样:Field('Amount','decimal(19,4)')
。但是,当我使用web2py的.executesql
方法从数据库返回一个值时,它返回的是float
而不是Decimal
。
编辑:这似乎是FreeTDS和MS SQL Server之间的问题。正如Massimo在评论中提到的,web2py对此支持得很好,并且会返回Decimal(如果可以的话)。结果发现这只是我生产环境(Linux)中的一个问题。我使用FreeTDS驱动程序连接到MS SQL,似乎它把MS SQL的money类型转换成了Python的float。
我觉得Alex Martelli的回答指向了正确的方向。有没有人对FreeTDS、MS SQL和Python有经验?我觉得这可能值得单独提问,所以我会把这个讨论移到其他地方……(新问题发布在这里:FreeTDS将MS SQL的money类型转换为Python的float,而不是Decimal)
更新:实际上,FreeTDS中确实有一个bug。这个问题在2010年8月4日的FreeTDS的CVS head
中已经被修复。
2 个回答
你可以写一个函数,这个函数先从数据库里获取数字,然后再把这个数字转换成小数。然后在你的代码中直接使用这个函数就可以了。
首先,确保数据库里的所有数字都用十进制形式存储。你没有提到你用的是什么数据库,但每种数据库都支持这种功能,比如这里是MySQL的DECIMAL
类型的说明。我希望你已经在这样做了,但如果还没有,进行一次数据库结构的修改也是值得的。
接下来,你需要确保在Python和数据库之间转换数据类型时,能够正确匹配数据库的十进制格式。可惜的是,不同的数据库接口实现没有统一的标准,但大多数都提供了一种方法;例如,使用MySQLDB时,你需要在connect
函数中传递一个conv=
参数,这个参数被称为“类型转换字典”——默认情况下,它是MySQLdb.converters.conversions
的一个副本,但你当然可以对它进行扩展,以便正确处理十进制数字。如果你告诉我们你使用的是哪个数据库,以及你喜欢的数据库接口包,我们可能能给你更详细的帮助。
编辑:@unutbu在评论中提到,当前的MySQLdb转换器已经能够正确转换十进制数字,所以,除非你使用的是非常旧的MySQLdb版本,只要你在数据库中正确地保持所有数字为十进制格式,就没问题了(太好了!)。