isinstance在AppEngine中不适用于Decimal

Aer*_*ert 5 python google-app-engine sqlalchemy decimal

我有一个decimal.Decimal来自SQLAlchemy查询的实例.因为我需要序列化对象,所以我创建了一个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)
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

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'
Run Code Online (Sandbox Code Playgroud)

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

编辑

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

isinstance(db.session.execute('SELECT amount FROM model LIMIT 1').fetchone()[0], decimal.Decimal)
Run Code Online (Sandbox Code Playgroud)

False通过AppEngine dev_appserver发出请求True时以及从控制台运行时返回.

mat*_*att 5

今天遇到了这个,并遇到了一个讨论这个的旧邮件列表帖子

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


似乎decimal.Decimal 类在Google App Engine SDK 中的某处打了补丁(或重新加载了模块),这是在导入decimal 的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
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)