Sorry, PEP 3106 is not yet accepted. Also removed mutating operations

and added some clarifications.
This commit is contained in:
Guido van Rossum 2007-02-20 23:32:28 +00:00
parent d6a8f11a3a
commit 7c97ac0ea4
2 changed files with 23 additions and 64 deletions

View File

@ -78,7 +78,7 @@ Index by Category
Accepted PEPs (accepted; may not be implemented yet)
SA 3102 Keyword-Only Arguments Talin
SA 3106 Revamping dict.keys(), .values() and .items() GvR
S 3106 Revamping dict.keys(), .values() and .items() GvR
SA 3107 Function Annotations Winter, Lownds
SA 3109 Raising Exceptions in Python 3000 Winter
SA 3110 Catching Exceptions in Python 3000 Winter
@ -449,7 +449,7 @@ Numerical Index
S 3103 A Switch/Case Statement GvR
S 3104 Access to Names in Outer Scopes Yee
SF 3105 Make print a function Brandl
SA 3106 Revamping dict.keys(), .values() and .items() GvR
S 3106 Revamping dict.keys(), .values() and .items() GvR
SA 3107 Function Annotations Winter, Lownds
I 3108 Standard Library Reorganization Cannon
SA 3109 Raising Exceptions in Python 3000 Winter

View File

@ -3,7 +3,7 @@ Title: Revamping dict.keys(), .values() and .items()
Version: $Revision$
Last-Modified: $Date$
Author: Guido van Rossum
Status: Accepted
Status: Draft
Type: Standards
Content-Type: text/x-rst
Created: 19-Dec-2006
@ -14,11 +14,10 @@ Abstract
========
This PEP proposes to change the .keys(), .values() and .items()
methods of the built-in dict type to return a set-like or
multiset-like (== bag-like) object whose contents are derived of the
underlying dictionary rather than a list which is a copy of the keys,
etc.; and to remove the .iterkeys(), .itervalues() and .iteritems()
methods.
methods of the built-in dict type to return a set-like or unordered
container object whose contents are derived of the underlying
dictionary rather than a list which is a copy of the keys, etc.; and
to remove the .iterkeys(), .itervalues() and .iteritems() methods.
The approach is inspired by that taken in the Java Collections
Framework [1]_.
@ -72,25 +71,16 @@ d.iterkeys() (etc.) does in Python 2.x; but in most contexts we don't
have to write the iter() call because it is implied by a for-loop.
The objects returned by the .keys() and .items() methods behave like
sets with limited mutability; they allow removing elements, but not
adding them. Removing an item from these sets removes it from the
underlying dict. The object returned by the values() method behaves
like a multiset (Java calls this a Collection). It does not allow
removing elements, because a value might occur multiple times and the
implementation wouldn't know which key to remove from the underlying
dict. (The Java Collections Framework has a way around this by
removing from an iterator, but I see no practical use case for that
functionality.)
sets. The object returned by the values() method behaves like a much
simpler unordered collection; anything more would require too much
implementation effort for the rare use case.
Because of the set behavior, it will be possible to check whether two
dicts have the same keys by simply testing::
if a.keys() == b.keys(): ...
and similarly for values. (Two multisets are deemed equal if they
have the same elements with the same cardinalities, e.g. the multiset
{1, 2, 2} is equal to the multiset {2, 1, 2} but differs from the
multiset {1, 2}.)
and similarly for .items().
These operations are thread-safe only to the extent that using them in
a thread-unsafe way may cause an exception but will not cause
@ -145,26 +135,12 @@ I'm using pseudo-code to specify the semantics::
for key in self.__d:
yield key
def remove(self, key):
del self.__d[key]
def discard(self, key):
if key in self:
self.remove(key)
def pop(self):
return self.__d.popitem()[0]
def clear(self):
self.__d.clear()
# The following operations should be implemented to be
# compatible with sets; this can be done by exploiting
# the above primitive operations:
#
# <, <=, ==, !=, >=, > (returning a bool)
# &, |, ^, - (returning a new, real set object)
# &=, -= (updating in place and returning self; but not |=, ^=)
#
# as well as their method counterparts (.union(), etc.).
#
@ -191,23 +167,6 @@ I'm using pseudo-code to specify the semantics::
for key in self.__d:
yield key, self.__d[key]
def remove(self, (key, value)):
if (key, value) not in self:
raise KeyError((key, value))
del self.__d[key]
def discard(self, item):
# Defined in terms of 'in' and .remove() so overriding
# those will update discard appropriately.
if item in self:
self.remove(item)
def pop(self):
return self.__d.popitem()
def clear(self):
self.__d.clear()
# As well as the set operations mentioned for d_keys above.
# However the specifications suggested there will not work if
# the values aren't hashable. Fortunately, the operations can
@ -288,11 +247,8 @@ I'm using pseudo-code to specify the semantics::
# XXX Sometimes this could be optimized, but these are the
# semantics: we can't depend on the values to be hashable
# or comparable.
o = list(other)
for x in self:
try:
o.remove(x)
except ValueError:
if not o in other:
return False
return True
@ -302,13 +258,21 @@ I'm using pseudo-code to specify the semantics::
result = not result
return result
Note that we don't implement .copy() -- the presence of a .copy()
Notes:
The view objects are not directly mutable, but don't implement
__hash__(); their value can change if the underlying dict is mutated.
The only requirements on the underlying dict are that it implements
__getitem__(), __contains__(), __iter__(), and __len__(0.
We don't implement .copy() -- the presence of a .copy()
method suggests that the copy has the same type as the original, but
that's not feasible without copying the underlying dict. If you want
a copy of a specific type, like list or set, you can just pass one
of the above to the list() or set() constructor.
Also note that the specification implies that the order in which items
The specification implies that the order in which items
are returned by .keys(), .values() and .items() is the same (just as
it was in Python 2.x), because the order is all derived from the dict
iterator (which is presumably arbitrary but stable as long as a dict
@ -325,7 +289,7 @@ set operations on keys and items without having to copy them should
speak for itself.
I've left out the implementation of various set operations. These
could still present surprises.
could still present small surprises.
It would be okay if multiple calls to d.keys() (etc.) returned the
same object, since the object's only state is the dict to which it
@ -334,11 +298,6 @@ Should that be a weak reference or should the d_keys (etc.) object
live forever once created? Strawman: probably not worth the extra
slots in every dict.
Should d_values have mutating methods (pop(), clear())? Strawman: no.
Should d_values implement set operations (as defined for multisets).
Strawman: no.
Should d_keys, d_values and d_items have a public instance variable or
method through which one can retrieve the underlying dict? Strawman:
yes (but what should it be called?).