lambda

Antoon Pardon apardon at forel.vub.ac.be
Wed Jan 19 15:40:24 CET 2005


Op 2005-01-19, Nick Coghlan schreef <ncoghlan at iinet.net.au>:
> Antoon Pardon wrote:
> 	> I can be wrong, but until now I have seen no indication that I was
>> using mutable and immutable differently than other people. AFAICT
>> we all refer to whether an object belongs to a mutable or immutable
>> class.
>
> The difference is that when you take a copy of the key and stick it in the 
> dictionary, such that the dictionary now holds the *sole* reference to that key, 
> you have made that key *effectively* immutable.
>
> This is why no-one really batted an eyelid when you mentioned that mutable keys 
> can be used safely by making a copy - doing so makes the key *effectively* 
> immutable, and means that modifying the original key object (i.e. the 
> application's copy, not the dict's copy), and reusing it to look up in the 
> dictionary is likely to give a KeyError.
>
> These semantics would be understandably surprising to many users, and hence, are 
> not supplied by default.

This seems like circle reasoning. The reason why these semantics would
be surprising is that those are not the semantics supplied.

> Additionally, a dictionary's keys are accessible via its API. Accordingly, to 
> preserve this 'effective immutability', making a copy on key input is 
> insufficient - keys must be copied on *output* as well (that is, dict.keys, 
> dict.items etc must return *copies* of the key objects, not the key objects 
> themselves).

Yes I haven been thinking about this too. I also think not making a copy
on output is less dangerous than not making a copy on input.

> Since there is no reliable way in Python to tell if an object is mutable or not 
> (the closest equivalent is the presence of __hash__, which clearly can't be used 
> in this example), this copying would need to be done for *every* object.
>
> Alternately, the dictionary can say to the API clients, "make an immutable copy 
> and supply that instead. It is left to API clients to decide how best to make 
> the immutable version". The API client copies the key once (to make the 
> immutable version), and everyone lives happily ever after.
>
> For example:
>
> Py> class mylist(list):
> ...   def __init__(self, arg):
> ...     super(mylist, self).__init__(arg)
> ...     self._tuple = None
> ...   def frozen(self):
> ...     if self._tuple is None:
> ...       self._tuple = tuple(self)
> ...     return self._tuple
> ...   def unfreeze(self):
> ...     self._tuple = None
> ...
> Py> x = mylist(range(10))
> Py> x
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
> Py> x.frozen()
> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
> Py> x.append(10)
> Py> x.frozen()
> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
> Py> x.unfreeze()
> Py> x.frozen()
> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
>
> This is much safer than having a list subclass that implements __hash__, and 
> still lets you avoid redundant copy operations.
>
> Nicely, so long as you don't unfreeze the object you used to key the dictionary, 
>   reusing the same object will always get you the correct dictionary entry, and 
> two lists that compare equal at the time they are frozen will also get you the 
> same dictionary entry. The equivalent tuples can be used for the lookup, too.

Interesting idea. But I think you are wrong when you say that two lists
that compare equal at the time they are frozen, will get the same
dictionary entry. The problem is an object must compare equal to
the key in the dictionary to get at the same entry. So if you freeze
a list and its copy but then mutate them differently, they no longer
are equal and so wont get you at the same entry.

[ Rest snipped, this is getting into a semantic debate on what
  'mutable' means. This may be interesting enough on its own
  but I feel it detracts too much from what I consider the
  more important issue. ]

-- 
Antoon Pardon



More information about the Python-list mailing list