Kaydet (Commit) 69eb5169 authored tarafından Alexandre Vassalotti's avatar Alexandre Vassalotti

Issue #1967: Backport dictionary views.

üst 7a8df802
...@@ -540,6 +540,13 @@ Glossary ...@@ -540,6 +540,13 @@ Glossary
object has a type. An object's type is accessible as its object has a type. An object's type is accessible as its
:attr:`__class__` attribute or can be retrieved with ``type(obj)``. :attr:`__class__` attribute or can be retrieved with ``type(obj)``.
view
The objects returned from :meth:`dict.viewkeys`, :meth:`dict.viewvalues`,
and :meth:`dict.viewitems` are called dictionary views. They are lazy
sequences that will see changes in the underlying dictionary. To force
the dictionary view to become a full list use ``list(dictview)``. See
:ref:`dict-views`.
virtual machine virtual machine
A computer defined entirely in software. Python's virtual machine A computer defined entirely in software. Python's virtual machine
executes the :term:`bytecode` emitted by the bytecode compiler. executes the :term:`bytecode` emitted by the bytecode compiler.
......
...@@ -2106,6 +2106,121 @@ pairs within braces, for example: ``{'jack': 4098, 'sjoerd': 4127}`` or ``{4098: ...@@ -2106,6 +2106,121 @@ pairs within braces, for example: ``{'jack': 4098, 'sjoerd': 4127}`` or ``{4098:
Return a copy of the dictionary's list of values. See the note for Return a copy of the dictionary's list of values. See the note for
:meth:`dict.items`. :meth:`dict.items`.
.. method:: viewitems()
Return a new view of the dictionary's items (``(key, value)`` pairs). See
below for documentation of view objects.
.. versionadded:: 2.7
.. method:: viewkeys()
Return a new view of the dictionary's keys. See below for documentation of
view objects.
.. versionadded:: 2.7
.. method:: viewvalues()
Return a new view of the dictionary's values. See below for documentation of
view objects.
.. versionadded:: 2.7
.. _dict-views:
Dictionary view objects
-----------------------
The objects returned by :meth:`dict.viewkeys`, :meth:`dict.viewvalues` and
:meth:`dict.viewitems` are *view objects*. They provide a dynamic view on the
dictionary's entries, which means that when the dictionary changes, the view
reflects these changes.
Dictionary views can be iterated over to yield their respective data, and
support membership tests:
.. describe:: len(dictview)
Return the number of entries in the dictionary.
.. describe:: iter(dictview)
Return an iterator over the keys, values or items (represented as tuples of
``(key, value)``) in the dictionary.
Keys and values are iterated over in an arbitrary order which is non-random,
varies across Python implementations, and depends on the dictionary's history
of insertions and deletions. If keys, values and items views are iterated
over with no intervening modifications to the dictionary, the order of items
will directly correspond. This allows the creation of ``(value, key)`` pairs
using :func:`zip`: ``pairs = zip(d.values(), d.keys())``. Another way to
create the same list is ``pairs = [(v, k) for (k, v) in d.items()]``.
Iterating views while adding or deleting entries in the dictionary may raise
a :exc:`RuntimeError` or fail to iterate over all entries.
.. describe:: x in dictview
Return ``True`` if *x* is in the underlying dictionary's keys, values or
items (in the latter case, *x* should be a ``(key, value)`` tuple).
Keys views are set-like since their entries are unique and hashable. If all
values are hashable, so that (key, value) pairs are unique and hashable, then
the items view is also set-like. (Values views are not treated as set-like
since the entries are generally not unique.) Then these set operations are
available ("other" refers either to another view or a set):
.. describe:: dictview & other
Return the intersection of the dictview and the other object as a new set.
.. describe:: dictview | other
Return the union of the dictview and the other object as a new set.
.. describe:: dictview - other
Return the difference between the dictview and the other object (all elements
in *dictview* that aren't in *other*) as a new set.
.. describe:: dictview ^ other
Return the symmetric difference (all elements either in *dictview* or
*other*, but not in both) of the dictview and the other object as a new set.
An example of dictionary view usage::
>>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500}
>>> keys = dishes.viewkeys()
>>> values = dishes.viewvalues()
>>> # iteration
>>> n = 0
>>> for val in values:
... n += val
>>> print(n)
504
>>> # keys and values are iterated over in the same order
>>> list(keys)
['eggs', 'bacon', 'sausage', 'spam']
>>> list(values)
[2, 1, 1, 500]
>>> # view objects are dynamic and reflect dict changes
>>> del dishes['eggs']
>>> del dishes['sausage']
>>> list(keys)
['spam', 'bacon']
>>> # set operations
>>> keys & {'eggs', 'bacon', 'salad'}
{'bacon'}
.. _bltin-file-objects: .. _bltin-file-objects:
......
...@@ -89,10 +89,22 @@ struct _dictobject { ...@@ -89,10 +89,22 @@ struct _dictobject {
}; };
PyAPI_DATA(PyTypeObject) PyDict_Type; PyAPI_DATA(PyTypeObject) PyDict_Type;
PyAPI_DATA(PyTypeObject) PyDictIterKey_Type;
PyAPI_DATA(PyTypeObject) PyDictIterValue_Type;
PyAPI_DATA(PyTypeObject) PyDictIterItem_Type;
PyAPI_DATA(PyTypeObject) PyDictKeys_Type;
PyAPI_DATA(PyTypeObject) PyDictItems_Type;
PyAPI_DATA(PyTypeObject) PyDictValues_Type;
#define PyDict_Check(op) \ #define PyDict_Check(op) \
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_DICT_SUBCLASS) PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_DICT_SUBCLASS)
#define PyDict_CheckExact(op) (Py_TYPE(op) == &PyDict_Type) #define PyDict_CheckExact(op) (Py_TYPE(op) == &PyDict_Type)
#define PyDictKeys_Check(op) (Py_TYPE(op) == &PyDictKeys_Type)
#define PyDictItems_Check(op) (Py_TYPE(op) == &PyDictItems_Type)
#define PyDictValues_Check(op) (Py_TYPE(op) == &PyDictValues_Type)
/* This excludes Values, since they are not sets. */
# define PyDictViewSet_Check(op) \
(PyDictKeys_Check(op) || PyDictItems_Check(op))
PyAPI_FUNC(PyObject *) PyDict_New(void); PyAPI_FUNC(PyObject *) PyDict_New(void);
PyAPI_FUNC(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key); PyAPI_FUNC(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key);
......
import unittest
from test import test_support
class DictSetTest(unittest.TestCase):
def test_constructors_not_callable(self):
kt = type({}.viewkeys())
self.assertRaises(TypeError, kt, {})
self.assertRaises(TypeError, kt)
it = type({}.viewitems())
self.assertRaises(TypeError, it, {})
self.assertRaises(TypeError, it)
vt = type({}.viewvalues())
self.assertRaises(TypeError, vt, {})
self.assertRaises(TypeError, vt)
def test_dict_keys(self):
d = {1: 10, "a": "ABC"}
keys = d.viewkeys()
self.assertEqual(len(keys), 2)
self.assertEqual(set(keys), set([1, "a"]))
self.assertEqual(keys, set([1, "a"]))
self.assertNotEqual(keys, set([1, "a", "b"]))
self.assertNotEqual(keys, set([1, "b"]))
self.assertNotEqual(keys, set([1]))
self.assertNotEqual(keys, 42)
self.assert_(1 in keys)
self.assert_("a" in keys)
self.assert_(10 not in keys)
self.assert_("Z" not in keys)
self.assertEqual(d.viewkeys(), d.viewkeys())
e = {1: 11, "a": "def"}
self.assertEqual(d.viewkeys(), e.viewkeys())
del e["a"]
self.assertNotEqual(d.viewkeys(), e.viewkeys())
def test_dict_items(self):
d = {1: 10, "a": "ABC"}
items = d.viewitems()
self.assertEqual(len(items), 2)
self.assertEqual(set(items), set([(1, 10), ("a", "ABC")]))
self.assertEqual(items, set([(1, 10), ("a", "ABC")]))
self.assertNotEqual(items, set([(1, 10), ("a", "ABC"), "junk"]))
self.assertNotEqual(items, set([(1, 10), ("a", "def")]))
self.assertNotEqual(items, set([(1, 10)]))
self.assertNotEqual(items, 42)
self.assert_((1, 10) in items)
self.assert_(("a", "ABC") in items)
self.assert_((1, 11) not in items)
self.assert_(1 not in items)
self.assert_(() not in items)
self.assert_((1,) not in items)
self.assert_((1, 2, 3) not in items)
self.assertEqual(d.viewitems(), d.viewitems())
e = d.copy()
self.assertEqual(d.viewitems(), e.viewitems())
e["a"] = "def"
self.assertNotEqual(d.viewitems(), e.viewitems())
def test_dict_mixed_keys_items(self):
d = {(1, 1): 11, (2, 2): 22}
e = {1: 1, 2: 2}
self.assertEqual(d.viewkeys(), e.viewitems())
self.assertNotEqual(d.viewitems(), e.viewkeys())
def test_dict_values(self):
d = {1: 10, "a": "ABC"}
values = d.viewvalues()
self.assertEqual(set(values), set([10, "ABC"]))
self.assertEqual(len(values), 2)
def test_dict_repr(self):
d = {1: 10, "a": "ABC"}
self.assertTrue(isinstance(repr(d), str))
self.assertTrue(isinstance(repr(d.viewitems()), str))
self.assertTrue(isinstance(repr(d.viewkeys()), str))
self.assertTrue(isinstance(repr(d.viewvalues()), str))
def test_main():
test_support.run_unittest(DictSetTest)
if __name__ == "__main__":
test_main()
...@@ -18,6 +18,8 @@ Core and Builtins ...@@ -18,6 +18,8 @@ Core and Builtins
- Issue #2333: Backport set and dict comprehensions syntax from Python 3.x. - Issue #2333: Backport set and dict comprehensions syntax from Python 3.x.
- Issue #1967: Backport dictionary views from Python 3.x.
Library Library
------- -------
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment