Python decimal.Decimal ID不一样 [英] Python decimal.Decimal id not the same

查看:185
本文介绍了Python decimal.Decimal ID不一样的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用Python对JSON进行编码时遇到问题,特别是使用decimal.Decimal值。我使用它为Google App Engine应用程序输出JSON。



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

  class DecimalEncoder json.JSONEncoder):
def default(self,o):
if isinstance(o,decimal.Decimal):
返回float(o)
返回超级(DecimalEncoder,self ).default(o)

在其他应用程序中,这确实起作用。在这种情况下,它不会。经过多次的挫折后,我发现这给出了奇怪的结果:

  print id(decimal.Decimal)
print id类型(o))

人们可能会认为id是相同的,因为它是相同的类对象只能在内存中驻留一次。由于ID的不同, isinstance()不起作用。



难道说decimal.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))
如果isinstance(o,decimal.Decimal):
返回float(o)
返回超级(DecimalEncoder,self).default(o)
$ b $ 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(
记录,
cls = Dec imalEncoder,
indent = 4,
separators =(',',':')
))

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

数据库表:

  CREATE TABLE`product`(
`id` int(11)unsigned NOT NULL AUTO_INCREMENT,
` (10,2)unsigned DEFAULT NULL,
PRIMARY KEY(`id`)
)ENGINE = InnoDB AUTO_INCREMENT = 0 DEFAULT CHARSET = utf8;
插入产品VALUES(0,5.00);


解决方案

看来 decimal .Decimal 类在Google App Engine SDK中的某处修补(或者模块被重新加载),这是在导入的MySQL转换库之间完成的。



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


MySQLdb.constants中的

 从MySQLdb.converters导入FIELD_TYPE 
导入转换
导入十进制

转换[FIELD_TYPE。 DECIMAL] = conversions [FIELD_TYPE.NEWDECIMAL] = decimal.Decimal

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



另一种方法是查找类 MySQLdb 正在使用:

$ $ p $ class DecimalEncoder(json.JSONEncoder):
def default(self,o ):
如果isinstance(o,MySQLdb.converters.conversions [MySQLdb.constants.FIELD_TYPE.DECIMAL]):
返回float(o)
返回超级(DecimalEncoder,self).default( o)


I am having a problem with encoding to JSON in Python, specifically with decimal.Decimal values. I am using this to output JSON for a Google App Engine application.

To circumvent the exception from the default json module in Python telling me that it can't handle decimal.Decimal objects, I am using this encoder subclass:

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

On other applications, this does work. In this case it doesn't. After much frustration I found out that this gives weird results:

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

One would expect the id's to be identical, because it makes sense for the same class object to reside only once in memory. Because the id's differ, isinstance() doesn't work.

Could it be that decimal.Decimal is already imported somewhere else, for instance in the App Engine and/or webapp2 packages?

The following modul reproduces the error on my system (OSx 10.10, Python 2.7.6, GAE SDK 1.9.20). Just create an GAE application and put this in 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)

Database table:

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);

解决方案

It appears that the decimal.Decimal class is patched somewhere in the Google App Engine SDK (or the module is reloaded), and this is done between the MySQL conversion library importing decimal and you importing the same.

Luckily, we can work around this by updating MySQL conversion table:

from MySQLdb.constants import FIELD_TYPE
from MySQLdb.converters import conversions
import decimal

conversions[FIELD_TYPE.DECIMAL] = conversions[FIELD_TYPE.NEWDECIMAL] = decimal.Decimal

That's it; the above code resets the MySQL class and your JSON encoder type check succeeds.

The alternative would be for you to look for the class MySQLdb is using:

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)

这篇关于Python decimal.Decimal ID不一样的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆