【问题标题】:isinstance not working for Decimal in AppEngineisinstance 不适用于 AppEngine 中的小数
【发布时间】:2016-12-22 00:03:27
【问题描述】:

我有一个来自 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

【问题讨论】:

  • obj.__class__ is blah.__class__ 的结果是什么?
  • @BrenBarn 这是False
  • 您的代码中似乎有缩进错误...return json.JSONEncoder.default(...) 应该在default 函数中。
  • @mgilson 干杯,它是 - 只是在将其复制到 SO 时出错。
  • 我们有没有可能重现这种奇怪的行为?

标签: python google-app-engine sqlalchemy decimal


【解决方案1】:

今天碰到这个,遇到了一个老的mailing list post 讨论这个。

原来这个问题也已经在on stackoverflow 之前得到了解决。在此处粘贴答案以方便访问/减少 stackoverflow 服务器负载:


看来,decimal.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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-25
    • 2013-07-02
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2014-12-22
    • 2011-04-07
    • 1970-01-01
    相关资源
    最近更新 更多