文章
· 一月 19, 2023 阅读大约需 4 分钟

在globals中序列化 Python 对象

动机

这个项目是在我考虑如何通过Embedded Python让Python代码自然地处理IRIS globals所提供的可扩展的存储和高效的检索机制时想到的。

我最初的想法是使用globals创建一种Python字典的实现,但很快我就意识到,我应该首先处理对象的抽象问题。

所以,我开始创建一些可以包装Python对象的Python类,在globals中存储和检索它们的数据,也就是说,在IRIS globals中序列化和反序列化Python对象。

它是如何工作的?

像 ObjectScript 的%DispatchGetProperty()%DispatchSetProperty() 和%DispatchMethod()一样, Python 有委托对象的属性和方法调用的方式。

当你设置或获取一个对象属性时,Python 解释器让你通过方式 __setattr__(self, name, value) 和 __getattr(self, name)__来截获这个操作。

请看这个相当基本的例子。

>>> class Test:
...         def __init(self, prop1):
...                 self.prop1 = prop1
...         def __setattr__(self, name, value):
...                 print(f"setting property {name} to value {value}")
...         def __getattr__(self, name):
...                 print(f"getting property {name}")
... 
>>> obj = Test()
>>> obj.prop1 = "test"
setting property prop1 to value test
>>> obj.prop1
getting property prop1
>>> obj.prop2
getting property prop2
>>> obj.prop2
getting property prop2
>>> 

注意方法 __setattr__() and __getattr()__ 是通过对 Test 类对象的 set 和 get 操作间接调用的 - 它实现了这些方法。即使是一个非声明的属性,如本例中的 prop2 也会对它们发出调用。

这种机制是我在项目python-globals-serializer-example中尝试的序列化测试的核心。 通过它,你可以拦截set/get操作,并从IRIS globals中存储/检索数据。

对象模型

Globals提供了一个高度可定制的结构。通过使用其信息访问的分层模型,这与JSON对象和Python字典相当相似,我们可以存储对象的属性数据和元数据。

下面是我如何使用 global 创建一个简单的对象模型来序列化 Python 对象:

对于每个序列化的对象,它的类名被序列化为一个标记为 "class "的节点:

^test(1,"class")="<class 'employee.SalaryEmployee'>"

第一个索引是一个递增的数字,在模型中作为这个对象的参考。所以,在上面的例子中,一个 employee.SalaryEmployee 类的对象被存储,参考值为1。

对于原始数据类型的属性,它们的类型和值被存储。例如:

^test(1,"name","type")="<class 'str'>"
^test(1,"name","value")="me"

这个结构被解释为索引1所指的对象,有一个叫做name的属性,其值等于'me'。

对于引用对象的属性来说,模型略有不同,因为与JSON对象或Python字典不同,globals旨在只存储原始数据类型的数据。所以另一个 “class”  节点被创建到这个被引用的对象上,它的节点索引( (i.e. its reference)  被存储在属性节点中:

^test(1,"company","oref")=2
^test(1,"company","type")="<class 'iris_global_object.IrisGlobalObject'>"
^test(2,"class")="<class 'employee.Company'>"
^test(2,"name","type")="<class 'str'>"
^test(2,"name","value")="Company ABC"

这些结构意味着对象1有一个名为 company的属性,它的值被存储在索引2中--注意^test(1,"company","oref")的值。

序列化/反序列化过程

当你创建一个包装器来序列化或反序列化 Python 对象时,你需要定义存储该对象的全局名称。

之后,在执行设置操作时,序列化过程就完成了。 __setattr__() 方法在定义的存储对象的global中设置属性值和类型,使用前面解释的简单对象模型。

在相反的方向,当一个获取操作被执行时,反序列化由 __getattr__ 方法完成。

对于原始数据类型,这个过程是简单明了的:只是获取存储在global中的值并返回。

但是对于对象,这个过程需要实例化它们的类数据类型,同时设置它们的所有属性,所以这样可以使用一个恢复的 Python 对象,包括对其方法的调用。

未来的工作

正如这篇文章的开头所说,这个项目的诞生是为了简化让Python代码使用全局作为自然存储引擎的方法,目的只是为了证明概念。

对对象进行序列化/反序列化只是这个目标的开始。所以,要让这个想法成熟,还需要做很多努力。

我希望这篇文章能让你了解我在这个项目中工作的目的,并可能启发你以新的方式思考如何使用IRIS globals,使Python更加接近IRIS。

讨论 (0)1
登录或注册以继续