【问题标题】:Custom Class Serialization with JSON in Python 3Python 3 中使用 JSON 的自定义类序列化
【发布时间】:2014-01-24 08:29:16
【问题描述】:

当 JSON 尝试使用 dict 中编码的类信息解码我的序列化自定义类时,我遇到了问题。我会尽量提供尽可能多的信息,所以请多多包涵。

我正在使用here 提供的优秀教程作为参考。我指的是详细说明为您自己的类编写编码/解码的部分。

我的包模块结构部分如下:

+--- PyDev Project
    +-- src
        +-- astar
        |    +-- __init__.py
        |    +-- astar.py
        +-- common
        |    +-- __init__.py
        |    +-- service.py
        |    +-- graph.py
        |    +-- vertex.py

每个模块都有自己的类。我正在序列化 common.service 模块中的 Service 类的对象。这基本上是通过 Pyro 连接使用的。

序列化代码为:

def convert_to_builtin_type(obj):
    print('default(', repr(obj), ')')
    # Convert objects to a dictionary of their representation
    d = { '__class__':obj.__class__.__name__, 
          '__module__':obj.__module__,
        }
d.update(obj.__dict__)
return d

反序列化代码为:

def dict_to_object(self, d):
    if '__class__' in d:
        class_name = d.pop('__class__')
        module_name = d.pop('__module__')
        # module = __import__(module_name)
        module = import_module(module_name)
        print('MODULE:', module)
        class_ = getattr(module, class_name)
        print('CLASS:', class_)
        args = dict( (key.encode('ascii'), value) for key, value in d.items())
        print('INSTANCE ARGS:', args)
        inst = class_(**args)
    else:
        inst = d
    return inst

反序列化期间出现问题。局部变量值为:

class_ = <module 'common.Service' from path-to-file.py>
class_name = 'Service'
module = <module 'common' from path-to-__init__.py>
module_name = 'common.Service'

失败的原因是 class_ 返回的是 package.module 值,而不是该模块内的类名。从技术上讲,class_ 应该包含 common.service.Service,这是实际的类。因此,最后一条语句 inst = class(**args)_ 因“TypeError: module object not callable”错误而失败。

我知道 import 或 importlib.import_module 都导入了顶级模块,但就我而言,我如何进入二级模块内的类?从技术上讲,第二层是模块,第一层是包,所以我需要 pkg.module 中的一个我无法访问的类。

我希望这个问题是有道理的,并且有足够的研究表明。如果需要澄清,我有更多信息。

编辑:用户建议解决了问题。

def dict_to_object(self, d):
    if '__class__' in d:
        class_name = d.pop('__class__')
        module_name = d.pop('__module__')
        # module = __import__(module_name)
        __import__(module_name)
        module = sys.modules[module_name]
        print('MODULE:', module)
        class_ = getattr(module, class_name)
        print('CLASS:', class_)
        args = dict((key, value) for key, value in d.items())
        print('INSTANCE ARGS:', args)
        inst = class_(**args)
    else:
        inst = d
    return inst

【问题讨论】:

    标签: json python-3.x pyro


    【解决方案1】:

    想法:

    1. 你的问题可能出在这一行:

      import_module(module_name)
      

      重新考虑您传递给该函数的参数。

    2. 知道 pickle 序列化程序会执行以下操作而不是 import_module

      import sys
      __import__(module_name)
      module = sys.modules[module_name]
      
    3. 在 Python 3 中也尝试使用 obj.__class__.__qualname__。它包括模块名称和嵌套类。

      class X:
           class Y: pass # __qualname__ includes X.Y
      
    4. 如果你之后发布工作代码我会很好,因为这可能是很多人的问题。

    【讨论】:

    • 感谢您的意见。第二种方法奏效了。使用 sys.import 有助于导入所有底层模块(就目前而言)。我在原始帖子中发布了工作修改代码。
    猜你喜欢
    • 1970-01-01
    • 2022-09-23
    • 2014-08-02
    • 1970-01-01
    • 2014-08-20
    • 1970-01-01
    • 2011-02-25
    • 2021-09-21
    • 1970-01-01
    相关资源
    最近更新 更多