包装Python对象

时间:2009-05-19 19:27:00

标签: python

我想将pl对象序列化为plist格式(这可以通过plistlib完成)。我的想法是编写一个包含其他对象的类PlistObject:

def __init__(self, anObject):
     self.theObject = anObject

并提供“写”方法:

def write(self, pathOrFile):
    plistlib.writeToPlist(self.theObject.__dict__, pathOrFile)

现在,如果PlistObject的行为与包装对象本身一样,那将是很好的,这意味着所有属性和方法都以某种方式“转发”到包装对象。我意识到方法__getattr____setattr__可以用于复杂的属性操作:

    def __getattr__(self, name):
         return self.theObject.__getattr__(name)

但是当然我遇到了构造函数现在产生无限递归的问题,因为self.theObject = anObject也尝试访问包装对象。

我该如何避免这种情况?如果整个想法看起来很糟糕,请告诉我。

3 个答案:

答案 0 :(得分:3)

除非我遗漏了什么,否则这样做会很好:

def __getattr__(self, name):
    return getattr(self.theObject, name)

修改:对于那些认为self.theObject的查询会导致对__getattr__的无限递归调用的人,让我告诉你:

>>> class Test:
...     a = "a"
...     def __init__(self):
...         self.b = "b"
...     def __getattr__(self, name):
...         return 'Custom: %s' % name
... 
>>> Test.a
'a'
>>> Test().a
'a'
>>> Test().b
'b'
>>> Test().c
'Custom: c'

__getattr__仅被称为last resort。由于可以在theObject中找到__dict__,因此不会出现任何问题。

答案 1 :(得分:2)

  

但是当然我遇到了构造函数现在产生无限递归的问题,因为self.theObject = anObject也试图访问包装对象。

这就是为什么手册建议您为所有“真正的”属性访问执行此操作。

theobj = object.__getattribute__(self, "theObject")

答案 2 :(得分:1)

我很高兴看到其他人能够帮助您对__getattr__进行递归调用。既然你已经要求对序列化到plist的一般方法发表评论,我只想提出一些想法。

Python的plist实现仅处理基本类型,并且没有提供扩展机制,您可以在序列化/反序列化复杂类型时指示它。例如,如果您定义了一个自定义类,那么writePlist将无法提供帮助,因为您已经发现,因为您要传递实例的__dict__以进行序列化。

这有几个含义:

  1. 您将无法使用此序列化包含非基本类型的其他对象的任何对象,而无需将它们转换为__dict__,并为整个网络图递归。

  2. 如果你推出自己的网络图形漫游器来序列化所有可以到达的非基本对象,你将不得不担心图形中的一个对象在一个属性中有另一个对象的情况,这反过来又持有引用回到第一个等等。

  3. 鉴于此,你可能希望看看pickle,因为它可以处理所有这些以及更多。如果由于其他原因需要plist格式,并且你确定你可以坚持使用“简单”对象dicts,那么你可能希望只使用一个简单的函数...试图让PlistObject模拟所包含的每个可能的函数object是一个洋葱,可能有很多层,因为你需要处理被包装实例的所有可能性。

    像这样简单的东西可能更加pythonic,并且通过不将它包装在第一位来保持包装对象的可用性更简单:

    def to_plist(obj, f_handle):
        writePlist(obj.__dict__, f_handle)
    

    我知道这看起来不太性感,但考虑到plist格式的严格限制,我认为它比包装器更易于维护,当然比人工强制应用程序中的所有对象继承自公共基类,当您的业务域中没有任何内容实际表明这些不同的对象是相关的时。