Re: [Zope3-Users] What attributes are made persistent

2006-02-16 Thread Chris Withers

Peter Bengtsson wrote:

So by using PersistentList it just means that you can use:
 self.alist.append(1)
in your code. The attribute, self.alist, is still saved even without
PersistentList but it just means you have to be careful when writing
to it.


PersistentX classes also usually subclass Persistent which means they 
get their own pickle jar. This can slow ZODB growth if you have lots of 
big attributes but where only one of them regularly changes: make the 
changing one a PersistentWhatever instance.


cheers,

Chris

--
Simplistix - Content Management, Zope  Python Consulting
   - http://www.simplistix.co.uk

___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-16 Thread Peter Bengtsson
On 2/16/06, Jeff Shell [EMAIL PROTECTED] wrote:
 One could, but it's really not worth it. It's just the laws of Python
 and mutability and immutability :). (It took me years to understand
 those terms. I kept associating them with 'mutable' in the can be
 made quiet sense... Eventually my music brain stepped back and I went
 oh, MUTATE! Ahhh!. Seriously, it took me about four years to
 understand that :).

Wow! I think I love you Jeff. Not only do you reply with
non-condencending constructive advise you also confess to [past]
weaknesses.


 Personally, I seldom store lists, or even use them as attributes on
 instances. Even outside of Zope/ZODB, I've found myself accidentally
 losing data because I was carelessly using the reference. Tuples for
 everybody!


Ok. Sounds sensible.
I've learnt something: use BTrees() instead of dict(), use tuple()
instead of list().


 On 2/15/06, Shaun Cutts [EMAIL PROTECTED] wrote:
  Well, one could have a base class along the lines of
 
  class PersistSetItemOnAttributes:
 
  def __setattr__( self, attr, val ):
  oldSI = val.__class__.__dict__.get( '__setitem__', None )
  if oldSI is not None:
  def newSI( vself, vattr, vval ):
  vself._p_changed = True # is this the right member?
  oldSI( vattr, vval )# oldSI is bound: no vself?
  val.__class__.__setitem__ = newSI
  super( PersistSetItemOnAttributes, self ).__setattr__( attr, val
  )
 
  Of course, this is really just pseudocode. For one thing, need to trap
  whether 'val' is really a class. For another if you were serious about
  this, you would want to check if the obj wasn't persistent first, and
  you might want to do it recursively. And while your are at it, you might
  want to check on other mutators as well(for instance, check first
  what sequence interface if any 'val' supports...)
 
  ... sounds like too much work, and would be problem prone even so. After
  all, some things you don't want to be persistent!
 
  - Shaun
 
   -Original Message-
   From: [EMAIL PROTECTED]
  [mailto:[EMAIL PROTECTED]
   On Behalf Of Stephan Richter
   Sent: Wednesday, February 15, 2006 8:43 AM
   To: zope3-users@zope.org
   Cc: Florian Lindner
   Subject: Re: [Zope3-Users] What attributes are made persistent
  
   On Wednesday 15 February 2006 08:21, Peter Bengtsson wrote:
class PersistentAnything(PersistentMapping, PersistentList,
PersistentDict):
  
   AA! This is so wrong! It merges two incompatible APIs: collections
  and
   mappings. The non-persistent equivalent to this is:
  
  class DoEverything(set, list, dict):
 ...  pass
  
Am I just trying to make it too simple?
  
   I think you try far too hard to not understand why the persistent
   mechanism
   works as it does. You make your life harder than it has to be.
  
   Regards,
   Stephan
   --
   Stephan Richter
   CBU Physics  Chemistry (B.S.) / Tufts Physics (Ph.D. student)
   Web2k - Web Software Design, Development and Training
   ___
   Zope3-users mailing list
   Zope3-users@zope.org
   http://mail.zope.org/mailman/listinfo/zope3-users
 
 
 
  ___
  Zope3-users mailing list
  Zope3-users@zope.org
  http://mail.zope.org/mailman/listinfo/zope3-users
 


 --
 Jeff Shell
 ___
 Zope3-users mailing list
 Zope3-users@zope.org
 http://mail.zope.org/mailman/listinfo/zope3-users



--
Peter Bengtsson,
work www.fry-it.com
home www.peterbe.com
hobby www.issuetrackerproduct.com
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-16 Thread Jean-Marc Orliaguet

Peter Bengtsson wrote:


On 2/16/06, Jeff Shell [EMAIL PROTECTED] wrote:
 


One could, but it's really not worth it. It's just the laws of Python
and mutability and immutability :). (It took me years to understand
those terms. I kept associating them with 'mutable' in the can be
made quiet sense... Eventually my music brain stepped back and I went
oh, MUTATE! Ahhh!. Seriously, it took me about four years to
understand that :).

   


Wow! I think I love you Jeff. Not only do you reply with
non-condencending constructive advise you also confess to [past]
weaknesses.

 


good try:-)
but that's a totally different ethymology, to mute is to make silent, 
to tone down (muet in French)


mutate c.1374, action of changing, from L. mutationem (nom. mutatio)
http://www.etymonline.com/index.php?search=mutate

/JM

___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-15 Thread Chris Withers

Peter Bengtsson wrote:

self.queue seem is empty each time I restart Zope.

That's because dictionaries are not derived from Persistent. Try PersistentDict.


D'oh! That's confusing. Isn't there a class that gathers all of these in one.


Urm, Peter, the rules of persistence w.r.t. mutable objects have been 
documented for a _long_ time. There's nothing Zope 3-specific here, and 
someone who's been using Zope as long as you should know better ;-)


Chris

--
Simplistix - Content Management, Zope  Python Consulting
   - http://www.simplistix.co.uk

___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-15 Thread Peter Bengtsson
-- Forwarded message --
From: Peter Bengtsson [EMAIL PROTECTED]
To: Jeff Shell [EMAIL PROTECTED]
Date: Wed, 15 Feb 2006 13:14:58 +
Subject: Re: [Zope3-Users] What attributes are made persistent
On 2/15/06, Jeff Shell [EMAIL PROTECTED] wrote:
 On 2/14/06, Peter Bengtsson [EMAIL PROTECTED] wrote:
  D'oh! That's confusing. Isn't there a class that gathers all of these in 
  one.
 
  It seems confusing, you derive from Persistent but only some are accepted.
  Does that mean that there's PersistentFloat and PersistentTuple too?
  If not, why *only* dicts?

 As mentioned above, it applies to *mutable* objects.



 Instances of Persistent based classes know when they change. Like if you do::

 clive.age = 28



 On the other hand, if you do::

 clive.favoriteNumbers.append(13)

 'clive' does not change. 'favoriteNumbers' changes. If favoriteNumbers
 is a regular Python list, the persistence machinery has no idea that
 it's changed. It's not being assigned to 'clive', it's already an
 attribute there and is not being replaced. So if it's not a
 PersistentList, it gets forgotten.



 It's not only dicts, it's dicts and lists (PersistentDict and PersistentList).

 I don't know if there's a PersistentSet. Python offers two sets since
 2.3 - a mutable (list-like) one and an immutable (tuple-like) one. I
 imagine that if you use the mutable set (``sets.Set`` in 2.3, ``set``
 in 2.4), you'd run into the same problems. But if you used the
 immutable set (``sets.ImmutableSet``, ``frozenset`` in 2.4) you
 wouldn't.



 So - just use PersistentList and PersistentDict (or look into BTrees
 for better storage options).

 For more details, visit the ZODB documentation on ZODB programming,
 and visit the section on modifying mutable objects:

 http://www.zope.org/Wikis/ZODB/FrontPage/guide/node3.html


I understand the mutation stuff and I always do it like this in zope2
(I'm a complete beginner in the zope3 world eager to learn):

def updatesometing(self):
   #self.numbers['Peter'] = 0779 123 456
   numbers = self.numbers
   numbers['Peter'] = 0779 123 456
   self.numbers = numbers

But in zope2 land, if I derive from Persistent it magically saves ALL
attributes defined in __init__ assuming that I post-write to them
correct as shown above.

I like this simplicity and was hoping to find it in zope3 land too. I
guess I'm just an old dog and if I want to drag with me the zope2 way
I can do this::

import persistent.mapping.PersistentMapping
import persistent.list.PersistentList
import persistent.dict.PersistentDict

class PersistentAnything(PersistentMapping, PersistentList, PersistentDict):

I'm aware of BTrees and am/will always use it when size of objects
becomes uncontrollable.

Am I just trying to make it too simple? Have I read one too many books
by Steve Krug?

--
Peter Bengtsson,
work www.fry-it.com
home www.peterbe.com
hobby www.issuetrackerproduct.com
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-15 Thread Paul Winkler
On Wed, Feb 15, 2006 at 01:21:14PM +, Peter Bengtsson wrote:
 I understand the mutation stuff and I always do it like this in zope2
 (I'm a complete beginner in the zope3 world eager to learn):
 
 def updatesometing(self):
#self.numbers['Peter'] = 0779 123 456
numbers = self.numbers
numbers['Peter'] = 0779 123 456
self.numbers = numbers
 
 But in zope2 land, if I derive from Persistent it magically saves ALL
 attributes defined in __init__ assuming that I post-write to them
 correct as shown above.

That hasn't changed in zope 3.  This is just standard ZODB behavior.
setattr will cause a save on commit regardless of the type of
the value.  If you read Jeff's reply again carefully, he said as much.

PersistentList and PersistentDict are not new, either.
They've been used in Zope 2 projects for ages.

There are still exactly three ways to get sub-object mutations to
persist:

1) Set the dirty bit by hand, e.g.:

 self.alist.append(1)
 self._p_changed = 1

2) Re-assign the attribute, e.g.:

 alist = self.alist
 alist.append(1)
 self.alist = alist

3) Using a persistent sub-object, e.g. a PersistentList instance:

 self.alist.append(1) 

-- 

Paul Winkler
http://www.slinkp.com
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-15 Thread Peter Bengtsson
On 2/15/06, Paul Winkler [EMAIL PROTECTED] wrote:
 On Wed, Feb 15, 2006 at 01:21:14PM +, Peter Bengtsson wrote:
  I understand the mutation stuff and I always do it like this in zope2
  (I'm a complete beginner in the zope3 world eager to learn):
 
  def updatesometing(self):
 #self.numbers['Peter'] = 0779 123 456
 numbers = self.numbers
 numbers['Peter'] = 0779 123 456
 self.numbers = numbers
 
  But in zope2 land, if I derive from Persistent it magically saves ALL
  attributes defined in __init__ assuming that I post-write to them
  correct as shown above.

 That hasn't changed in zope 3.  This is just standard ZODB behavior.
 setattr will cause a save on commit regardless of the type of
 the value.  If you read Jeff's reply again carefully, he said as much.

 PersistentList and PersistentDict are not new, either.
 They've been used in Zope 2 projects for ages.

 There are still exactly three ways to get sub-object mutations to
 persist:

 1) Set the dirty bit by hand, e.g.:

  self.alist.append(1)
  self._p_changed = 1

 2) Re-assign the attribute, e.g.:

  alist = self.alist
  alist.append(1)
  self.alist = alist

 3) Using a persistent sub-object, e.g. a PersistentList instance:

  self.alist.append(1)



Now I get it! Sorry for being slow and thanks for explaining.

So by using PersistentList it just means that you can use:
 self.alist.append(1)
in your code. The attribute, self.alist, is still saved even without
PersistentList but it just means you have to be careful when writing
to it.

Cool!

--
Peter Bengtsson,
work www.fry-it.com
home www.peterbe.com
hobby www.issuetrackerproduct.com
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-15 Thread Lennart Regebro
On 2/15/06, Peter Bengtsson [EMAIL PROTECTED] wrote:
 D'oh! That's confusing. Isn't there a class that gathers all of these in one.

All of who?

 It seems confusing, you derive from Persistent but only some are accepted.
 Does that mean that there's PersistentFloat and PersistentTuple too?

Because floats and tuples are not mutable. You can't change them, so
the don't need to know that they should be persisted when changed.

 If not, why *only* dicts?

There is also PersistentList.

--
Lennart Regebro, Nuxeo http://www.nuxeo.com/
CPS Content Management http://www.cps-project.org/
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


RE: [Zope3-Users] What attributes are made persistent

2006-02-15 Thread Shaun Cutts
Well, one could have a base class along the lines of

class PersistSetItemOnAttributes:

def __setattr__( self, attr, val ):
oldSI = val.__class__.__dict__.get( '__setitem__', None )
if oldSI is not None:
def newSI( vself, vattr, vval ):
vself._p_changed = True # is this the right member?
oldSI( vattr, vval )# oldSI is bound: no vself?
val.__class__.__setitem__ = newSI
super( PersistSetItemOnAttributes, self ).__setattr__( attr, val
)

Of course, this is really just pseudocode. For one thing, need to trap
whether 'val' is really a class. For another if you were serious about
this, you would want to check if the obj wasn't persistent first, and
you might want to do it recursively. And while your are at it, you might
want to check on other mutators as well(for instance, check first
what sequence interface if any 'val' supports...)

... sounds like too much work, and would be problem prone even so. After
all, some things you don't want to be persistent!

- Shaun
 
 -Original Message-
 From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED]
 On Behalf Of Stephan Richter
 Sent: Wednesday, February 15, 2006 8:43 AM
 To: zope3-users@zope.org
 Cc: Florian Lindner
 Subject: Re: [Zope3-Users] What attributes are made persistent
 
 On Wednesday 15 February 2006 08:21, Peter Bengtsson wrote:
  class PersistentAnything(PersistentMapping, PersistentList,
  PersistentDict):
 
 AA! This is so wrong! It merges two incompatible APIs: collections
and
 mappings. The non-persistent equivalent to this is:
 
class DoEverything(set, list, dict):
   ...  pass
 
  Am I just trying to make it too simple?
 
 I think you try far too hard to not understand why the persistent
 mechanism
 works as it does. You make your life harder than it has to be.
 
 Regards,
 Stephan
 --
 Stephan Richter
 CBU Physics  Chemistry (B.S.) / Tufts Physics (Ph.D. student)
 Web2k - Web Software Design, Development and Training
 ___
 Zope3-users mailing list
 Zope3-users@zope.org
 http://mail.zope.org/mailman/listinfo/zope3-users



___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


[Zope3-Users] What attributes are made persistent

2006-02-14 Thread Florian Lindner
Hello,
in a class derived from Persistent, which attributes are stored? All or only 
those thar are declared in the interface?

def __init__(self):
self.queue = {}


self.queue seem is empty each time I restart Zope.

Thanks,

Florian
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-14 Thread Gary Poster


On Feb 14, 2006, at 4:52 PM, Florian Lindner wrote:


Hello,
in a class derived from Persistent, which attributes are stored?  
All or only

those thar are declared in the interface?


All.


def __init__(self):
self.queue = {}


self.queue seem is empty each time I restart Zope.


Mutable objects, such as sets, lists, and dicts, can't inform their  
persistent parents when they change, so changes to them are not  
persisted.  Use a persistent mapping in the persistent package (or a  
btree); or set obj._p_changed=True when the dict changes; or use an  
immutable data structure that must be replaced on the object instead.


Gary
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-14 Thread Lennart Regebro
On 2/14/06, Florian Lindner [EMAIL PROTECTED] wrote:
 Hello,
 in a class derived from Persistent, which attributes are stored? All or only
 those thar are declared in the interface?

All.

 def __init__(self):
 self.queue = {}


 self.queue seem is empty each time I restart Zope.

That's because dictionaries are not derived from Persistent. Try PersistentDict.

--
Lennart Regebro, Nuxeo http://www.nuxeo.com/
CPS Content Management http://www.cps-project.org/
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-14 Thread Peter Bengtsson
On 2/14/06, Lennart Regebro [EMAIL PROTECTED] wrote:
 On 2/14/06, Florian Lindner [EMAIL PROTECTED] wrote:
  Hello,
  in a class derived from Persistent, which attributes are stored? All or only
  those thar are declared in the interface?

 All.

  def __init__(self):
  self.queue = {}
 
 
  self.queue seem is empty each time I restart Zope.

 That's because dictionaries are not derived from Persistent. Try 
 PersistentDict.

D'oh! That's confusing. Isn't there a class that gathers all of these in one.

It seems confusing, you derive from Persistent but only some are accepted.
Does that mean that there's PersistentFloat and PersistentTuple too?
If not, why *only* dicts?

 --
 Lennart Regebro, Nuxeo http://www.nuxeo.com/
 CPS Content Management http://www.cps-project.org/
 ___
 Zope3-users mailing list
 Zope3-users@zope.org
 http://mail.zope.org/mailman/listinfo/zope3-users



--
Peter Bengtsson,
work www.fry-it.com
home www.peterbe.com
hobby www.issuetrackerproduct.com
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-14 Thread Tom Dossis

Peter Bengtsson wrote:



   def __init__(self):
   self.queue = {}


self.queue seem is empty each time I restart Zope.

That's because dictionaries are not derived from Persistent. Try PersistentDict.


D'oh! That's confusing. Isn't there a class that gathers all of these in one.

It seems confusing, you derive from Persistent but only some are accepted.
Does that mean that there's PersistentFloat and PersistentTuple too?
If not, why *only* dicts?


No, this issue applies to mutable attributes..

self.a = 1.1
self.b = (1,2,3)
self.b = (4,5,6)

These will persist as is, because you're rebinding the attribute 
(reference) each time.


However, for ...

self.queue[1] = 2

This doesn't rebind self.queue.
So another way you could 'persist' this change is ..

self.queue[1] = 1
self.queue = self.queue
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-14 Thread Jeff Shell
On 2/14/06, Peter Bengtsson [EMAIL PROTECTED] wrote:
 D'oh! That's confusing. Isn't there a class that gathers all of these in one.

 It seems confusing, you derive from Persistent but only some are accepted.
 Does that mean that there's PersistentFloat and PersistentTuple too?
 If not, why *only* dicts?

As mentioned above, it applies to *mutable* objects.


Objects whose value can change are said to be mutable; objects whose
value is unchangeable once they are created are called immutable. (The
value of an immutable container object that contains a reference to a
mutable object can change when the latter's value is changed; however
the container is still considered immutable, because the collection of
objects it contains cannot be changed. So, immutability is not
strictly the same as having an unchangeable value, it is more subtle.)
An object's mutability is determined by its type; for instance,
numbers, strings and tuples are immutable, while dictionaries and
lists are mutable.

http://docs.python.org/ref/objects.html

Instances of Persistent based classes know when they change. Like if you do::

clive.age = 28

Which is effectively ``setattr(clive, 'age', 28)``. As a persistent
object, clive notices that an attribute is being set (even if it's
replacing an existing value), and flags that 'clive' has changes that
need to be saved. So again - here, it's the 'clive' object that's
being updated in this case. The fact that the value is an integer
doesn't matter. It's not changing. 28 is 28. But 'clive' is changing
by having a new/updated 'age' attribute set.

On the other hand, if you do::

clive.favoriteNumbers.append(13)

'clive' does not change. 'favoriteNumbers' changes. If favoriteNumbers
is a regular Python list, the persistence machinery has no idea that
it's changed. It's not being assigned to 'clive', it's already an
attribute there and is not being replaced. So if it's not a
PersistentList, it gets forgotten.

If favoriteNumbers was a tuple, you couldn't append to it. You could
do an addition, but in a form like this::

clive.favoriteNumbers = clive.favoriteNumbers + (13,)
# Alternately
clive.favoriteNumbers += (13,)

This is doing assignment. 'clive' is getting a new attribute set, and
as a Persistent object 'clive' can be set as needing its changes
saved.

It's not only dicts, it's dicts and lists (PersistentDict and PersistentList).

I don't know if there's a PersistentSet. Python offers two sets since
2.3 - a mutable (list-like) one and an immutable (tuple-like) one. I
imagine that if you use the mutable set (``sets.Set`` in 2.3, ``set``
in 2.4), you'd run into the same problems. But if you used the
immutable set (``sets.ImmutableSet``, ``frozenset`` in 2.4) you
wouldn't.

Note that this issue affects not just ZODB persistence. If you used
even the simple 'shelve' module that's in Python, you have the same
issue unless you use a 'writeback' option:


If the writeback parameter is True, the object will hold a cache of
all entries accessed and write them back to the dict at sync and close
times. This allows natural operations on mutable entries, but can
consume much more memory and make sync and close take a long time.


So as a way of making working with default mutable objects feel
natural, this option makes shelve read and write its whole database,
which would obviously be very expensive for the ZODB.

So - just use PersistentList and PersistentDict (or look into BTrees
for better storage options).

For more details, visit the ZODB documentation on ZODB programming,
and visit the section on modifying mutable objects:

http://www.zope.org/Wikis/ZODB/FrontPage/guide/node3.html
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


Re: [Zope3-Users] What attributes are made persistent

2006-02-14 Thread Jeff Shell
Oh! And reference to related Persistence modules (persistent mappings,
lists, BTrees):

http://www.zope.org/Wikis/ZODB/FrontPage/guide/node6.html

On 2/14/06, Jeff Shell [EMAIL PROTECTED] wrote:
 On 2/14/06, Peter Bengtsson [EMAIL PROTECTED] wrote:
  D'oh! That's confusing. Isn't there a class that gathers all of these in 
  one.
 
  It seems confusing, you derive from Persistent but only some are accepted.
  Does that mean that there's PersistentFloat and PersistentTuple too?
  If not, why *only* dicts?

 As mentioned above, it applies to *mutable* objects.

 
 Objects whose value can change are said to be mutable; objects whose
 value is unchangeable once they are created are called immutable. (The
 value of an immutable container object that contains a reference to a
 mutable object can change when the latter's value is changed; however
 the container is still considered immutable, because the collection of
 objects it contains cannot be changed. So, immutability is not
 strictly the same as having an unchangeable value, it is more subtle.)
 An object's mutability is determined by its type; for instance,
 numbers, strings and tuples are immutable, while dictionaries and
 lists are mutable.
 
 http://docs.python.org/ref/objects.html

 Instances of Persistent based classes know when they change. Like if you do::

 clive.age = 28

 Which is effectively ``setattr(clive, 'age', 28)``. As a persistent
 object, clive notices that an attribute is being set (even if it's
 replacing an existing value), and flags that 'clive' has changes that
 need to be saved. So again - here, it's the 'clive' object that's
 being updated in this case. The fact that the value is an integer
 doesn't matter. It's not changing. 28 is 28. But 'clive' is changing
 by having a new/updated 'age' attribute set.

 On the other hand, if you do::

 clive.favoriteNumbers.append(13)

 'clive' does not change. 'favoriteNumbers' changes. If favoriteNumbers
 is a regular Python list, the persistence machinery has no idea that
 it's changed. It's not being assigned to 'clive', it's already an
 attribute there and is not being replaced. So if it's not a
 PersistentList, it gets forgotten.

 If favoriteNumbers was a tuple, you couldn't append to it. You could
 do an addition, but in a form like this::

 clive.favoriteNumbers = clive.favoriteNumbers + (13,)
 # Alternately
 clive.favoriteNumbers += (13,)

 This is doing assignment. 'clive' is getting a new attribute set, and
 as a Persistent object 'clive' can be set as needing its changes
 saved.

 It's not only dicts, it's dicts and lists (PersistentDict and PersistentList).

 I don't know if there's a PersistentSet. Python offers two sets since
 2.3 - a mutable (list-like) one and an immutable (tuple-like) one. I
 imagine that if you use the mutable set (``sets.Set`` in 2.3, ``set``
 in 2.4), you'd run into the same problems. But if you used the
 immutable set (``sets.ImmutableSet``, ``frozenset`` in 2.4) you
 wouldn't.

 Note that this issue affects not just ZODB persistence. If you used
 even the simple 'shelve' module that's in Python, you have the same
 issue unless you use a 'writeback' option:

 
 If the writeback parameter is True, the object will hold a cache of
 all entries accessed and write them back to the dict at sync and close
 times. This allows natural operations on mutable entries, but can
 consume much more memory and make sync and close take a long time.
 

 So as a way of making working with default mutable objects feel
 natural, this option makes shelve read and write its whole database,
 which would obviously be very expensive for the ZODB.

 So - just use PersistentList and PersistentDict (or look into BTrees
 for better storage options).

 For more details, visit the ZODB documentation on ZODB programming,
 and visit the section on modifying mutable objects:

 http://www.zope.org/Wikis/ZODB/FrontPage/guide/node3.html



--
Jeff Shell
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users