Writing persistent classes Persistent if reachable from the root Persistency by storing/loading...
-
Upload
vanessa-mcconnell -
Category
Documents
-
view
218 -
download
1
Transcript of Writing persistent classes Persistent if reachable from the root Persistency by storing/loading...
![Page 1: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/1.jpg)
Writing persistent classes
• Persistent if reachable from the root
• Persistency by storing/loading pickles
• ZODB must know when an object is accessed or changed
• Automatic (transparent) for attribute access
• Some common Python idioms require explicit interactions
![Page 2: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/2.jpg)
Persistence by reachability
• Persistent object must be reachable from the root object, which ZODB creates automatically
myPersistentObj = PersistentObj()
conn.root()[‘coll’] = myPersistentObject
![Page 3: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/3.jpg)
Saved state is a pickle
• Objects to be stored in ZODB must be picklable.
• Normally, an object’s attributes (__dict__) are pickled by ZODB for storing, and the pickle is unserialized into __dict__ for loading.
• Persistent captures all attribute access via __getattr__() and __setattr__() hooks
![Page 4: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/4.jpg)
Subobjects
• Subobjects are pickled by value, except:– if they are Persistent, they’re pickled by “persistent id”
– Classes, modules, and functions are pickled by “fully qualified name”
– Upon unpickling instances, __init__() is not called unless the class defines an __getinitargs__() method.
– See the Python 2.2 docs for pickle module for more rules regarding extension types, etc.
![Page 5: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/5.jpg)
Mutable attributes
• Object has an attribute that’s a mutable Python object, e.g. dictionary or list
• Changes to the mutable object are not caught by ZODB, so you have to help it out
>>> person.appointments
[]
>>> person.appointments.append(app)
>>> person._p_changed = 1
![Page 6: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/6.jpg)
PersistentMapping
• Class provided by ZODB for persistent, near-dictionary-like semantics
• It fiddles with _p_changed for you:>>> person.contacts
<PersistentMapping instance at 81445d8>
>>> person.contacts[‘Barry’] = barry
>>> get_transaction().commit()
![Page 7: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/7.jpg)
PersistentList?
• Not part of Zope Corp’s distribution (yet)
• Andrew Kuchling’s SourceForge project has one (zodb.sf.net)
• Provides list-like semantics while taking care of _p_changed fiddling
![Page 8: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/8.jpg)
Unpicklable objects
class F(Persistent):
def __init__(self, filename):
self.fp = open(filename)
>>> root[‘files’] = F(‘/etc/passwd’)
>>> get_transaction().commit()
…
cPickle.UnpicklableError: cannot pickle <type ‘file’> objects
![Page 9: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/9.jpg)
Unpicklable objects
class F(Persistent):def __init__(self, filename):
self.fp = open(filename)def __getstate__(self):
return self.fp.namedef __setstate__(self, filename):
self.fp = open(filename)>>> root[‘files’] = F(‘/etc/passwd’)>>> get_transaction().commit()>>>
![Page 10: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/10.jpg)
Volatile attributes
• Attributes not to be stored persistently should be prefixed with _v_
class F(Persistent):
def __init__(self, filename):
self._v_fp = open(filename)
>>> root[‘files’] = F(‘/etc/passwd’)
>>> get_transaction().commit()
# later…
>>> root[‘files’].__dict__
{}
![Page 11: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/11.jpg)
Python special methods
• Persistent classes can’t define reversed binary operators like __radd__ and __rsub__
• Older versions had some problems with __cmp__() and (maybe) __hash__()
• Persistent classes won’t track new __ methods introduced in Python 2.2 and beyond.
![Page 12: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/12.jpg)
Managing object evolution
• Classes can change by adding, deleting, or redefining methods, or adding and deleting attributes.
• Changes to methods “just work” because classes are stored by reference, not by value
• Changes to attributes can be handled by __setstate__() method, or by off-line update script
![Page 13: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/13.jpg)
__setstate__()
class Person(Persistent):
def __init__(self, name):
self.name = name
>>> barry = Person(‘Barry Warsaw’)
>>> root[‘people’][‘barry’] = barry
>>> get_transaction().commit()
![Page 14: Writing persistent classes Persistent if reachable from the root Persistency by storing/loading pickles ZODB must know when an object is accessed or changed.](https://reader036.fdocuments.in/reader036/viewer/2022082700/551507c0550346a87d8b46a0/html5/thumbnails/14.jpg)
__setstate__() con’t
class Person(Persistent):
def __init__(self, username, realname):
self.username = username
self.realname = realname
def __setstate__(self, d):
self.realname = name = d[‘name’]
username = name.split()[0].lower()
self.username = username