isinstance在AppEngine中不适用于Decimal

时间:2016-12-22 00:03:27

标签: python google-app-engine sqlalchemy decimal

我有一个来自SQLAlchemy查询的decimal.Decimal实例。由于我需要序列化对象,我创建了一个JSON序列化程序来处理Decimal

import decimal
class AlchemyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, decimal.Decimal):
            return str(obj)
        return json.JSONEncoder.default(self, obj)

不幸的是isinstance(obj, decimal.Decimal)没有为实例返回True,即使(在上面的default方法中使用pdb):

obj.__class__ # => <class 'decimal.Decimal'>
blah = decimal.Decimal()
blah.__class__ # => <class 'decimal.Decimal'>
isinstance(obj, decimal.Decimal) # => False
isinstance(blah, decimal.Decimal) # => True
isinstance(obj, obj.__class__) # => True

我确实检查了两个实例引用的模块是同一个模块:

import inspect
inspect.getfile(obj.__class__) # => '/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/decimal.pyc'
inspect.getfile(blah.__class__) # => '/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/decimal.pyc'

我真的很想知道为什么这不起作用!

修改

事实证明,只有在AppEngine的dev_appserver.py环境下运行时才会出现此问题。一个简单的:

isinstance(db.session.execute('SELECT amount FROM model LIMIT 1').fetchone()[0], decimal.Decimal)
当从控制台运行时,

通过AppEngine dev_appserver和False发出请求时返回True

1 个答案:

答案 0 :(得分:3)

今天进入这个,并遇到了一个讨论过这个问题的旧mailing list post

事实证明,此问题也已在on stackoverflow中得到解决。在此处粘贴答案以便于访问/减少stackoverflow服务器负载:

看来,十进制.Decimal类在Google App Engine SDK中的某个位置打了补丁(或重新加载了模块),这是在MySQL转换库导入十进制和导入十进制之间完成的。

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

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

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

就是这样;上面的代码重置了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)