<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>2.5.1 Modifying Mutable Objects</title> <META NAME="description" CONTENT="2.5.1 Modifying Mutable Objects"> <META NAME="keywords" CONTENT="zodb"> <META NAME="resource-type" CONTENT="document"> <META NAME="distribution" CONTENT="global"> <meta http-equiv="Content-Type" content="text/html; charset="> <link rel="STYLESHEET" href="zodb.css"> <link rel="first" href="zodb.html"> <link rel="contents" href="contents.html" title="Contents"> <LINK REL="next" HREF="node17.html"> <LINK REL="previous" HREF="node15.html"> <LINK REL="up" HREF="node15.html"> <LINK REL="next" HREF="node17.html"> </head> <body> <DIV CLASS="navigation"> <table align="center" width="100%" cellpadding="0" cellspacing="2"> <tr> <td><A HREF="node15.html"><img src="/python/writing/icons/previous.gif" border="0" height="32" alt="Previous Page" width="32"></A></td> <td><A HREF="node15.html"><img src="/python/writing/icons/up.gif" border="0" height="32" alt="Up One Level" width="32"></A></td> <td><A HREF="node17.html"><img src="/python/writing/icons/next.gif" border="0" height="32" alt="Next Page" width="32"></A></td> <td align="center" width="100%">ZODB/ZEO Programming Guide</td> <td><A href="contents.html"><img src="/python/writing/icons/contents.gif" border="0" height="32" alt="Contents" width="32"></A></td> <td><img src="/python/writing/icons/blank.gif" border="0" height="32" alt="" width="32"></td> <td><img src="/python/writing/icons/blank.gif" border="0" height="32" alt="" width="32"></td> </tr></table> <b class="navlabel">Previous:</b> <a class="sectref" HREF="node15.html">2.5 Rules for Writing</A> <b class="navlabel">Up:</b> <a class="sectref" HREF="node15.html">2.5 Rules for Writing</A> <b class="navlabel">Next:</b> <a class="sectref" HREF="node17.html">2.5.2 Some Special Methods</A> <br><hr> </DIV> <!--End of Navigation Panel--> <H3><A NAME="SECTION000351000000000000000"> 2.5.1 Modifying Mutable Objects</A> </H3> <P> The ZODB uses various Python hooks to catch attribute accesses, and can trap most of the ways of modifying an object, but not all of them. If you modify a <tt class="class">User</tt> object by assigning to one of its attributes, as in <code>userobj.first_name = 'Andrew'</code>, the ZODB will mark the object as having been changed, and it'll be written out on the following <tt class="method">commit()</tt>. <P> The most common idiom that <i>isn't</i> caught by the ZODB is mutating a list or dictionary. If <tt class="class">User</tt> objects have a attribute named <code>friends</code> containing a list, calling <code>userobj.friends.append(otherUser)</code> doesn't mark <code>userobj</code> as modified; from the ZODB's point of view, <code>userobj.friends</code> was only read, and its value, which happened to be an ordinary Python list, was returned. The ZODB isn't aware that the object returned was subsequently modified. <P> This is one of the few quirks you'll have to remember when using the ZODB; if you modify a mutable attribute of an object in place, you have to manually mark the object as having been modified by setting its dirty bit to true. This is done by setting the <tt class="member">_p_changed</tt> attribute of the object to true: <P> <dl><dd><pre class="verbatim"> userobj.friends.append(otherUser) userobj._p_changed = 1 </pre></dl> <P> An obsolete way of doing this that's still supported is calling the <tt class="method">__changed__()</tt> method instead, but setting <tt class="member">_p_changed</tt> is the preferred way. <P> You can hide the implementation detail of having to mark objects as dirty by designing your class's API to not use direct attribute access; instead, you can use the Java-style approach of accessor methods for everything, and then set the dirty bit within the accessor method. For example, you might forbid accessing the <code>friends</code> attribute directly, and add a <tt class="method">get_friend_list()</tt> accessor and an <tt class="method">add_friend()</tt> modifier method to the class. <tt class="method">add_friend()</tt> would then look like this: <P> <dl><dd><pre class="verbatim"> def add_friend(self, friend): self.friends.append(otherUser) self._p_changed = 1 </pre></dl> <P> Alternatively, you could use a ZODB-aware list or mapping type that handles the dirty bit for you. The ZODB comes with a <tt class="class">PersistentMapping</tt> class, and I've contributed a <tt class="class">PersistentList</tt> class that's included in my ZODB distribution, and may make it into a future upstream release of Zope. <P> <DIV CLASS="navigation"> <p><hr> <table align="center" width="100%" cellpadding="0" cellspacing="2"> <tr> <td><A HREF="node15.html"><img src="/python/writing/icons/previous.gif" border="0" height="32" alt="Previous Page" width="32"></A></td> <td><A HREF="node15.html"><img src="/python/writing/icons/up.gif" border="0" height="32" alt="Up One Level" width="32"></A></td> <td><A HREF="node17.html"><img src="/python/writing/icons/next.gif" border="0" height="32" alt="Next Page" width="32"></A></td> <td align="center" width="100%">ZODB/ZEO Programming Guide</td> <td><A href="contents.html"><img src="/python/writing/icons/contents.gif" border="0" height="32" alt="Contents" width="32"></A></td> <td><img src="/python/writing/icons/blank.gif" border="0" height="32" alt="" width="32"></td> <td><img src="/python/writing/icons/blank.gif" border="0" height="32" alt="" width="32"></td> </tr></table> <b class="navlabel">Previous:</b> <a class="sectref" HREF="node15.html">2.5 Rules for Writing</A> <b class="navlabel">Up:</b> <a class="sectref" HREF="node15.html">2.5 Rules for Writing</A> <b class="navlabel">Next:</b> <a class="sectref" HREF="node17.html">2.5.2 Some Special Methods</A> <hr> <span class="release-info">Release 0.03, documentation updated on February 8, 2002.</span> </DIV> <!--End of Navigation Panel--> </BODY> </HTML>