Python decimal.Decimal id不一样

时间:2015-06-07 14:06:38

标签: python json google-app-engine decimal

我遇到了在Python中使用JSON编码的问题,特别是使用decimal.Decimal值。我正在使用它为Google App Engine应用程序输出JSON。

为了避免Python中的默认json模块的异常,告诉我它不能处理decimal.Decimal对象,我正在使用这个编码器子类:

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            return float(o)
        return super(DecimalEncoder, self).default(o)

在其他应用程序上,这确实有效。在这种情况下,它没有。经过多次挫折后,我发现这会产生奇怪的结果:

print id(decimal.Decimal)
print id(type(o))

人们会期望id是相同的,因为同一个类对象只能在内存中驻留一次是有意义的。由于ID不同,isinstance()无效。

可能是十进制.Decimal已经导入其他地方了,例如在App Engine和/或webapp2包中?

以下模块重现了我系统上的错误(OSx 10.10,Python 2.7.6,GAE SDK 1.9.20)。只需创建一个GAE应用程序并将其放在main.py中:

import webapp2, decimal, json, MySQLdb, sys

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        print id(decimal.Decimal)
        print id(type(o))
        if isinstance(o, decimal.Decimal):
            return float(o)
        return super(DecimalEncoder, self).default(o)

class MainHandler(webapp2.RequestHandler):
    def get(self):
        db = MySQLdb.connect(unix_socket='/var/mysql/mysql.sock', host='localhost', user='root', db='ssss', charset='utf8')
        cursor = db.cursor(MySQLdb.cursors.DictCursor)
        cursor.execute("SELECT id, price FROM product WHERE id = 1")
        record = cursor.fetchone()

        self.response.headers['Content-Type'] = 'application/json'
        self.response.write(json.dumps(
            record,
            cls=DecimalEncoder,
            indent=4,
            separators=(',', ': ')
        ))

app = webapp2.WSGIApplication([
    ('/', MainHandler)
], debug=True)

数据库表:

CREATE TABLE `product` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `price` decimal(10,2) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
INSERT INTO product VALUES(0, 5.00);

1 个答案:

答案 0 :(得分:7)

似乎decimal.Decimal类已在Google App Engine SDK中修补某处(或重新加载模块),这是在MySQL转换库导入{{1}之间完成的并导入相同的内容。

幸运的是,我们可以通过更新MySQL转换表来解决这个问题:

decimal

就是这样;上面的代码重置了MySQL类,你的JSON编码器类型检查成功。

替代方法是让您查找正在使用的课程from MySQLdb.constants import FIELD_TYPE from MySQLdb.converters import conversions import decimal conversions[FIELD_TYPE.DECIMAL] = conversions[FIELD_TYPE.NEWDECIMAL] = decimal.Decimal

MySQLdb