Wrapping a Python Object
I would like to serialize Python objects to and from plist format (this can be done with plistlib). My idea was to write a PlistObject class that wraps other objects:
def __init__(self, anObject):
self.theObject = anObject
and provides a "write" method:
def write(self, pathOrFile):
plistlib.writeToPlist(self.theObject.__dict__, pathOrFile)
Now it would be nice if the PlistObject behaves just like the wrapped object itself, which means that all the attributes and methods are somehow "redirected" to the wrapped object. I understand that methods __getattr__
and __setattr__
can be used for complex operations on attributes:
def __getattr__(self, name):
return self.theObject.__getattr__(name)
But then, of course, I ran into the problem that the constructor is now doing infinite recursion as it also self.theObject = anObject
tries to access the wrapped object.
How can I avoid this? If the whole idea seems bad, tell me too.
a source to share
But then of course I ran into the problem that the constructor is now creating an infinite recursion since self.theObject = anObject is trying to access the wrapped object.
This is why the manual suggests that you do this for all "real" attribute accesses.
theobj = object.__getattribute__(self, "theObject")
a source to share
If I haven't missed something, this would be pretty good:
def __getattr__(self, name):
return getattr(self.theObject, name)
Edit: for those who think searching self.theObject
will result in an infinite recursive call __getattr__
, let me show you:
>>> 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__
only called the last resort . Since theObject
it can be found in __dict__
, there are no problems.
a source to share
I'm glad to see others have been able to help you with the recursive call __getattr__
. Since you were asking for comment on the general serialization approach to plist, I just wanted to call back with a few thoughts.
The Python plist implementation only handles basic types and does not provide an extension mechanism for you to instruct on serializing / deserializing complex types. If you are defining your own class, for example, writePlist will not be able to help, as you found out, since you are passing an instance __dict__
to serialize.
This has several consequences:
-
You cannot use this to serialize any objects that contain other non-base objects without converting them to
__dict__
and so on recursively for the entire network. -
If you flip your own network walker graph to serialize all non-core objects that can be reached, you have to worry about circles in the graph where one object has a different property, which in turn is a reference to the first, etc. etc.
As such, you might want to take a look at pickle because it can handle all of this and more. If you need the plist format for other reasons and you are sure you can stick with "simple" dicts then you can just use a simple function ... trying to make the PlistObject layout every possible function in the contained object is a bow with potentially many layers since you need to handle all the possibilities of the wrapped instance.
Something as simple as this might be more pythonic, and make it easier to use a wrapped object without wrapping it in the first place:
def to_plist(obj, f_handle):
writePlist(obj.__dict__, f_handle)
I know it doesn't look very sexy, but in my opinion it is much more convenient than a wrapper given the tight constraints of the plist format and is certainly better than artificially forcing all objects in your application to inherit from a common base class when there is nothing in your business domain that actually points to those disparate entities.
a source to share