Reb*_*ner 1 python google-app-engine json decimal
我在Python中使用JSON编码时出现问题,特别是使用decimal.Decimal值.我正在使用它为Google App Engine应用程序输出JSON.
为了绕过jsonPython中的默认模块的异常,告诉我它无法处理decimal.Decimal对象,我正在使用这个编码器子类:
class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return float(o)
return super(DecimalEncoder, self).default(o)
Run Code Online (Sandbox Code Playgroud)
在其他应用程序上,这确实有效.在这种情况下,它没有.经过多次挫折后,我发现这给出了奇怪的结果:
print id(decimal.Decimal)
print id(type(o))
Run Code Online (Sandbox Code Playgroud)
人们会期望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)
Run Code Online (Sandbox Code Playgroud)
数据库表:
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);
Run Code Online (Sandbox Code Playgroud)
似乎decimal.Decimal该类已在Google App Engine SDK中的某个位置进行了修补(或重新加载了该模块),这是在MySQL转换库导入decimal和导入之前完成的.
幸运的是,我们可以通过更新MySQL转换表来解决这个问题:
from MySQLdb.constants import FIELD_TYPE
from MySQLdb.converters import conversions
import decimal
conversions[FIELD_TYPE.DECIMAL] = conversions[FIELD_TYPE.NEWDECIMAL] = decimal.Decimal
Run Code Online (Sandbox Code Playgroud)
而已; 上面的代码重置MySQL类,你的JSON编码器类型检查成功.
替代方法是让您查找MySQLdb正在使用的类:
class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, MySQLdb.converters.conversions[MySQLdb.constants.FIELD_TYPE.DECIMAL]):
return float(o)
return super(DecimalEncoder, self).default(o)
Run Code Online (Sandbox Code Playgroud)