<!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>