Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
6531bf63
Commit
6531bf63
authored
Nov 06, 2018
by
Rémi Lapeyre
Committed by
INADA Naoki
Nov 06, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bpo-33462: Add __reversed__ to dict and dict views (GH-6827)
parent
16c8a534
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
346 additions
and
24 deletions
+346
-24
Doc/library/stdtypes.rst
Doc/library/stdtypes.rst
+29
-0
Doc/whatsnew/3.8.rst
Doc/whatsnew/3.8.rst
+3
-0
Include/dictobject.h
Include/dictobject.h
+3
-0
Lib/test/test_collections.py
Lib/test/test_collections.py
+12
-13
Lib/test/test_dict.py
Lib/test/test_dict.py
+66
-3
Lib/test/test_enumerate.py
Lib/test/test_enumerate.py
+2
-2
Misc/NEWS.d/next/Core and Builtins/2018-05-23-17-18-02.bpo-33462.gurbpbrhe.rst
... and Builtins/2018-05-23-17-18-02.bpo-33462.gurbpbrhe.rst
+1
-0
Objects/clinic/dictobject.c.h
Objects/clinic/dictobject.c.h
+19
-1
Objects/dictobject.c
Objects/dictobject.c
+202
-5
Objects/object.c
Objects/object.c
+9
-0
No files found.
Doc/library/stdtypes.rst
View file @
6531bf63
...
@@ -4285,6 +4285,11 @@ pairs within braces, for example: ``{'jack': 4098, 'sjoerd': 4127}`` or ``{4098:
...
@@ -4285,6 +4285,11 @@ pairs within braces, for example: ``{'jack': 4098, 'sjoerd': 4127}`` or ``{4098:
LIFO order is now guaranteed. In prior versions, :meth:`popitem` would
LIFO order is now guaranteed. In prior versions, :meth:`popitem` would
return an arbitrary key/value pair.
return an arbitrary key/value pair.
.. describe:: reversed(d)
Return a reversed iterator over the keys of the dictionary. This is a
shortcut for ``reversed(d.keys())``.
.. method:: setdefault(key[, default])
.. method:: setdefault(key[, default])
If *key* is in the dictionary, return its value. If not, insert *key*
If *key* is in the dictionary, return its value. If not, insert *key*
...
@@ -4332,6 +4337,22 @@ pairs within braces, for example: ``{'jack': 4098, 'sjoerd': 4127}`` or ``{4098:
...
@@ -4332,6 +4337,22 @@ pairs within braces, for example: ``{'jack': 4098, 'sjoerd': 4127}`` or ``{4098:
Dictionary order is guaranteed to be insertion order. This behavior was
Dictionary order is guaranteed to be insertion order. This behavior was
implementation detail of CPython from 3.6.
implementation detail of CPython from 3.6.
Dictionaries and dictionary views are reversible. ::
>>> d = {"one": 1, "two": 2, "three": 3, "four": 4}
>>> d
{'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> list(reversed(d))
['four', 'three', 'two', 'one']
>>> list(reversed(d.values()))
[4, 3, 2, 1]
>>> list(reversed(d.items()))
[('four', 4), ('three', 3), ('two', 2), ('one', 1)]
.. versionchanged:: 3.8
Dictionaries are now reversible.
.. seealso::
.. seealso::
:class:`types.MappingProxyType` can be used to create a read-only view
:class:`types.MappingProxyType` can be used to create a read-only view
of a :class:`dict`.
of a :class:`dict`.
...
@@ -4375,6 +4396,14 @@ support membership tests:
...
@@ -4375,6 +4396,14 @@ support membership tests:
Return ``True`` if *x* is in the underlying dictionary's keys, values or
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).
items (in the latter case, *x* should be a ``(key, value)`` tuple).
.. describe:: reversed(dictview)
Return an reversed iterator over the keys, values or items of the dictionnary.
The view will be iterated in reverse order of the insertion.
.. versionchanged:: 3.8
Dictionary views are now reversible.
Keys views are set-like since their entries are unique and hashable. If all
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,
values are hashable, so that ``(key, value)`` pairs are unique and hashable,
...
...
Doc/whatsnew/3.8.rst
View file @
6531bf63
...
@@ -98,6 +98,9 @@ Other Language Changes
...
@@ -98,6 +98,9 @@ Other Language Changes
* Added support of ``\N{name}`` escapes in :mod:`regular expressions <re>`.
* Added support of ``\N{name}`` escapes in :mod:`regular expressions <re>`.
(Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.)
(Contributed by Jonathan Eunice and Serhiy Storchaka in :issue:`30688`.)
* Dict and dictviews are now iterable in reversed insertion order using
:func:`reversed`. (Contributed by Rémi Lapeyre in :issue:`33462`.)
* The syntax allowed for keyword names in function calls was further
* The syntax allowed for keyword names in function calls was further
restricted. In particular, ``f((keyword)=arg)`` is no longer allowed. It was
restricted. In particular, ``f((keyword)=arg)`` is no longer allowed. It was
never intended to permit more than a bare name on the left-hand side of a
never intended to permit more than a bare name on the left-hand side of a
...
...
Include/dictobject.h
View file @
6531bf63
...
@@ -51,6 +51,9 @@ PyAPI_DATA(PyTypeObject) PyDict_Type;
...
@@ -51,6 +51,9 @@ PyAPI_DATA(PyTypeObject) PyDict_Type;
PyAPI_DATA
(
PyTypeObject
)
PyDictIterKey_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictIterKey_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictIterValue_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictIterValue_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictIterItem_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictIterItem_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictRevIterKey_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictRevIterItem_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictRevIterValue_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictKeys_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictKeys_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictItems_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictItems_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictValues_Type
;
PyAPI_DATA
(
PyTypeObject
)
PyDictValues_Type
;
...
...
Lib/test/test_collections.py
View file @
6531bf63
...
@@ -796,22 +796,21 @@ class TestOneTrickPonyABCs(ABCTestCase):
...
@@ -796,22 +796,21 @@ class TestOneTrickPonyABCs(ABCTestCase):
def
test_Reversible
(
self
):
def
test_Reversible
(
self
):
# Check some non-reversibles
# Check some non-reversibles
non_samples
=
[
None
,
42
,
3.14
,
1j
,
dict
(),
set
(),
frozenset
()]
non_samples
=
[
None
,
42
,
3.14
,
1j
,
set
(),
frozenset
()]
for
x
in
non_samples
:
for
x
in
non_samples
:
self
.
assertNotIsInstance
(
x
,
Reversible
)
self
.
assertNotIsInstance
(
x
,
Reversible
)
self
.
assertFalse
(
issubclass
(
type
(
x
),
Reversible
),
repr
(
type
(
x
)))
self
.
assertFalse
(
issubclass
(
type
(
x
),
Reversible
),
repr
(
type
(
x
)))
# Check some non-reversible iterables
# Check some non-reversible iterables
non_reversibles
=
[
dict
().
keys
(),
dict
().
items
(),
dict
().
values
(),
non_reversibles
=
[
_test_gen
(),
(
x
for
x
in
[]),
iter
([]),
reversed
([])]
Counter
(),
Counter
().
keys
(),
Counter
().
items
(),
Counter
().
values
(),
_test_gen
(),
(
x
for
x
in
[]),
iter
([]),
reversed
([])]
for
x
in
non_reversibles
:
for
x
in
non_reversibles
:
self
.
assertNotIsInstance
(
x
,
Reversible
)
self
.
assertNotIsInstance
(
x
,
Reversible
)
self
.
assertFalse
(
issubclass
(
type
(
x
),
Reversible
),
repr
(
type
(
x
)))
self
.
assertFalse
(
issubclass
(
type
(
x
),
Reversible
),
repr
(
type
(
x
)))
# Check some reversible iterables
# Check some reversible iterables
samples
=
[
bytes
(),
str
(),
tuple
(),
list
(),
OrderedDict
(),
samples
=
[
bytes
(),
str
(),
tuple
(),
list
(),
OrderedDict
(),
OrderedDict
().
keys
(),
OrderedDict
().
items
(),
OrderedDict
().
keys
(),
OrderedDict
().
items
(),
OrderedDict
().
values
()]
OrderedDict
().
values
(),
Counter
(),
Counter
().
keys
(),
Counter
().
items
(),
Counter
().
values
(),
dict
(),
dict
().
keys
(),
dict
().
items
(),
dict
().
values
()]
for
x
in
samples
:
for
x
in
samples
:
self
.
assertIsInstance
(
x
,
Reversible
)
self
.
assertIsInstance
(
x
,
Reversible
)
self
.
assertTrue
(
issubclass
(
type
(
x
),
Reversible
),
repr
(
type
(
x
)))
self
.
assertTrue
(
issubclass
(
type
(
x
),
Reversible
),
repr
(
type
(
x
)))
...
@@ -1612,7 +1611,7 @@ class TestCollectionABCs(ABCTestCase):
...
@@ -1612,7 +1611,7 @@ class TestCollectionABCs(ABCTestCase):
self
.
assertIsInstance
(
z
,
set
)
self
.
assertIsInstance
(
z
,
set
)
list
(
z
)
list
(
z
)
mymap
[
'blue'
]
=
7
# Shouldn't affect 'z'
mymap
[
'blue'
]
=
7
# Shouldn't affect 'z'
self
.
assertEqual
(
sorted
(
z
),
[(
'orange'
,
3
),
(
'red'
,
5
)]
)
self
.
assertEqual
(
z
,
{(
'orange'
,
3
),
(
'red'
,
5
)}
)
def
test_Sequence
(
self
):
def
test_Sequence
(
self
):
for
sample
in
[
tuple
,
list
,
bytes
,
str
]:
for
sample
in
[
tuple
,
list
,
bytes
,
str
]:
...
@@ -1767,10 +1766,10 @@ class TestCounter(unittest.TestCase):
...
@@ -1767,10 +1766,10 @@ class TestCounter(unittest.TestCase):
self
.
assertTrue
(
issubclass
(
Counter
,
Mapping
))
self
.
assertTrue
(
issubclass
(
Counter
,
Mapping
))
self
.
assertEqual
(
len
(
c
),
3
)
self
.
assertEqual
(
len
(
c
),
3
)
self
.
assertEqual
(
sum
(
c
.
values
()),
6
)
self
.
assertEqual
(
sum
(
c
.
values
()),
6
)
self
.
assertEqual
(
sorted
(
c
.
values
()),
[
1
,
2
,
3
])
self
.
assertEqual
(
list
(
c
.
values
()),
[
3
,
2
,
1
])
self
.
assertEqual
(
sorted
(
c
.
keys
()),
[
'a'
,
'b'
,
'c'
])
self
.
assertEqual
(
list
(
c
.
keys
()),
[
'a'
,
'b'
,
'c'
])
self
.
assertEqual
(
sorted
(
c
),
[
'a'
,
'b'
,
'c'
])
self
.
assertEqual
(
list
(
c
),
[
'a'
,
'b'
,
'c'
])
self
.
assertEqual
(
sorted
(
c
.
items
()),
self
.
assertEqual
(
list
(
c
.
items
()),
[(
'a'
,
3
),
(
'b'
,
2
),
(
'c'
,
1
)])
[(
'a'
,
3
),
(
'b'
,
2
),
(
'c'
,
1
)])
self
.
assertEqual
(
c
[
'b'
],
2
)
self
.
assertEqual
(
c
[
'b'
],
2
)
self
.
assertEqual
(
c
[
'z'
],
0
)
self
.
assertEqual
(
c
[
'z'
],
0
)
...
@@ -1784,7 +1783,7 @@ class TestCounter(unittest.TestCase):
...
@@ -1784,7 +1783,7 @@ class TestCounter(unittest.TestCase):
for
i
in
range
(
5
):
for
i
in
range
(
5
):
self
.
assertEqual
(
c
.
most_common
(
i
),
self
.
assertEqual
(
c
.
most_common
(
i
),
[(
'a'
,
3
),
(
'b'
,
2
),
(
'c'
,
1
)][:
i
])
[(
'a'
,
3
),
(
'b'
,
2
),
(
'c'
,
1
)][:
i
])
self
.
assertEqual
(
''
.
join
(
sorted
(
c
.
elements
()
)),
'aaabbc'
)
self
.
assertEqual
(
''
.
join
(
c
.
elements
(
)),
'aaabbc'
)
c
[
'a'
]
+=
1
# increment an existing value
c
[
'a'
]
+=
1
# increment an existing value
c
[
'b'
]
-=
2
# sub existing value to zero
c
[
'b'
]
-=
2
# sub existing value to zero
del
c
[
'c'
]
# remove an entry
del
c
[
'c'
]
# remove an entry
...
@@ -1793,7 +1792,7 @@ class TestCounter(unittest.TestCase):
...
@@ -1793,7 +1792,7 @@ class TestCounter(unittest.TestCase):
c
[
'e'
]
=
-
5
# directly assign a missing value
c
[
'e'
]
=
-
5
# directly assign a missing value
c
[
'f'
]
+=
4
# add to a missing value
c
[
'f'
]
+=
4
# add to a missing value
self
.
assertEqual
(
c
,
dict
(
a
=
4
,
b
=
0
,
d
=-
2
,
e
=-
5
,
f
=
4
))
self
.
assertEqual
(
c
,
dict
(
a
=
4
,
b
=
0
,
d
=-
2
,
e
=-
5
,
f
=
4
))
self
.
assertEqual
(
''
.
join
(
sorted
(
c
.
elements
()
)),
'aaaaffff'
)
self
.
assertEqual
(
''
.
join
(
c
.
elements
(
)),
'aaaaffff'
)
self
.
assertEqual
(
c
.
pop
(
'f'
),
4
)
self
.
assertEqual
(
c
.
pop
(
'f'
),
4
)
self
.
assertNotIn
(
'f'
,
c
)
self
.
assertNotIn
(
'f'
,
c
)
for
i
in
range
(
3
):
for
i
in
range
(
3
):
...
...
Lib/test/test_dict.py
View file @
6531bf63
...
@@ -1021,7 +1021,7 @@ class DictTest(unittest.TestCase):
...
@@ -1021,7 +1021,7 @@ class DictTest(unittest.TestCase):
it
=
iter
(
data
)
it
=
iter
(
data
)
d
=
pickle
.
dumps
(
it
,
proto
)
d
=
pickle
.
dumps
(
it
,
proto
)
it
=
pickle
.
loads
(
d
)
it
=
pickle
.
loads
(
d
)
self
.
assertEqual
(
sorted
(
it
),
sorted
(
data
))
self
.
assertEqual
(
list
(
it
),
list
(
data
))
it
=
pickle
.
loads
(
d
)
it
=
pickle
.
loads
(
d
)
try
:
try
:
...
@@ -1031,7 +1031,7 @@ class DictTest(unittest.TestCase):
...
@@ -1031,7 +1031,7 @@ class DictTest(unittest.TestCase):
d
=
pickle
.
dumps
(
it
,
proto
)
d
=
pickle
.
dumps
(
it
,
proto
)
it
=
pickle
.
loads
(
d
)
it
=
pickle
.
loads
(
d
)
del
data
[
drop
]
del
data
[
drop
]
self
.
assertEqual
(
sorted
(
it
),
sorted
(
data
))
self
.
assertEqual
(
list
(
it
),
list
(
data
))
def
test_itemiterator_pickling
(
self
):
def
test_itemiterator_pickling
(
self
):
for
proto
in
range
(
pickle
.
HIGHEST_PROTOCOL
+
1
):
for
proto
in
range
(
pickle
.
HIGHEST_PROTOCOL
+
1
):
...
@@ -1062,7 +1062,7 @@ class DictTest(unittest.TestCase):
...
@@ -1062,7 +1062,7 @@ class DictTest(unittest.TestCase):
it
=
iter
(
data
.
values
())
it
=
iter
(
data
.
values
())
d
=
pickle
.
dumps
(
it
,
proto
)
d
=
pickle
.
dumps
(
it
,
proto
)
it
=
pickle
.
loads
(
d
)
it
=
pickle
.
loads
(
d
)
self
.
assertEqual
(
sorted
(
list
(
it
)),
sorted
(
list
(
data
.
values
()
)))
self
.
assertEqual
(
list
(
it
),
list
(
data
.
values
(
)))
it
=
pickle
.
loads
(
d
)
it
=
pickle
.
loads
(
d
)
drop
=
next
(
it
)
drop
=
next
(
it
)
...
@@ -1071,6 +1071,62 @@ class DictTest(unittest.TestCase):
...
@@ -1071,6 +1071,62 @@ class DictTest(unittest.TestCase):
values
=
list
(
it
)
+
[
drop
]
values
=
list
(
it
)
+
[
drop
]
self
.
assertEqual
(
sorted
(
values
),
sorted
(
list
(
data
.
values
())))
self
.
assertEqual
(
sorted
(
values
),
sorted
(
list
(
data
.
values
())))
def
test_reverseiterator_pickling
(
self
):
for
proto
in
range
(
pickle
.
HIGHEST_PROTOCOL
+
1
):
data
=
{
1
:
"a"
,
2
:
"b"
,
3
:
"c"
}
it
=
reversed
(
data
)
d
=
pickle
.
dumps
(
it
,
proto
)
it
=
pickle
.
loads
(
d
)
self
.
assertEqual
(
list
(
it
),
list
(
reversed
(
data
)))
it
=
pickle
.
loads
(
d
)
try
:
drop
=
next
(
it
)
except
StopIteration
:
continue
d
=
pickle
.
dumps
(
it
,
proto
)
it
=
pickle
.
loads
(
d
)
del
data
[
drop
]
self
.
assertEqual
(
list
(
it
),
list
(
reversed
(
data
)))
def
test_reverseitemiterator_pickling
(
self
):
for
proto
in
range
(
pickle
.
HIGHEST_PROTOCOL
+
1
):
data
=
{
1
:
"a"
,
2
:
"b"
,
3
:
"c"
}
# dictviews aren't picklable, only their iterators
itorg
=
reversed
(
data
.
items
())
d
=
pickle
.
dumps
(
itorg
,
proto
)
it
=
pickle
.
loads
(
d
)
# note that the type of the unpickled iterator
# is not necessarily the same as the original. It is
# merely an object supporting the iterator protocol, yielding
# the same objects as the original one.
# self.assertEqual(type(itorg), type(it))
self
.
assertIsInstance
(
it
,
collections
.
abc
.
Iterator
)
self
.
assertEqual
(
dict
(
it
),
data
)
it
=
pickle
.
loads
(
d
)
drop
=
next
(
it
)
d
=
pickle
.
dumps
(
it
,
proto
)
it
=
pickle
.
loads
(
d
)
del
data
[
drop
[
0
]]
self
.
assertEqual
(
dict
(
it
),
data
)
def
test_reversevaluesiterator_pickling
(
self
):
for
proto
in
range
(
pickle
.
HIGHEST_PROTOCOL
):
data
=
{
1
:
"a"
,
2
:
"b"
,
3
:
"c"
}
# data.values() isn't picklable, only its iterator
it
=
reversed
(
data
.
values
())
d
=
pickle
.
dumps
(
it
,
proto
)
it
=
pickle
.
loads
(
d
)
self
.
assertEqual
(
list
(
it
),
list
(
reversed
(
data
.
values
())))
it
=
pickle
.
loads
(
d
)
drop
=
next
(
it
)
d
=
pickle
.
dumps
(
it
,
proto
)
it
=
pickle
.
loads
(
d
)
values
=
list
(
it
)
+
[
drop
]
self
.
assertEqual
(
sorted
(
values
),
sorted
(
data
.
values
()))
def
test_instance_dict_getattr_str_subclass
(
self
):
def
test_instance_dict_getattr_str_subclass
(
self
):
class
Foo
:
class
Foo
:
def
__init__
(
self
,
msg
):
def
__init__
(
self
,
msg
):
...
@@ -1222,6 +1278,13 @@ class DictTest(unittest.TestCase):
...
@@ -1222,6 +1278,13 @@ class DictTest(unittest.TestCase):
self
.
assertRaises
(
RuntimeError
,
iter_and_mutate
)
self
.
assertRaises
(
RuntimeError
,
iter_and_mutate
)
def
test_reversed
(
self
):
d
=
{
"a"
:
1
,
"b"
:
2
,
"foo"
:
0
,
"c"
:
3
,
"d"
:
4
}
del
d
[
"foo"
]
r
=
reversed
(
d
)
self
.
assertEqual
(
list
(
r
),
list
(
'dcba'
))
self
.
assertRaises
(
StopIteration
,
next
,
r
)
def
test_dict_copy_order
(
self
):
def
test_dict_copy_order
(
self
):
# bpo-34320
# bpo-34320
od
=
collections
.
OrderedDict
([(
'a'
,
1
),
(
'b'
,
2
)])
od
=
collections
.
OrderedDict
([(
'a'
,
1
),
(
'b'
,
2
)])
...
...
Lib/test/test_enumerate.py
View file @
6531bf63
...
@@ -160,9 +160,9 @@ class TestReversed(unittest.TestCase, PickleTest):
...
@@ -160,9 +160,9 @@ class TestReversed(unittest.TestCase, PickleTest):
raise
StopIteration
raise
StopIteration
def
__len__
(
self
):
def
__len__
(
self
):
return
5
return
5
for
data
in
'abc'
,
range
(
5
),
tuple
(
enumerate
(
'abc'
)),
A
(),
range
(
1
,
17
,
5
):
for
data
in
(
'abc'
,
range
(
5
),
tuple
(
enumerate
(
'abc'
)),
A
(),
range
(
1
,
17
,
5
),
dict
.
fromkeys
(
'abcde'
)):
self
.
assertEqual
(
list
(
data
)[::
-
1
],
list
(
reversed
(
data
)))
self
.
assertEqual
(
list
(
data
)[::
-
1
],
list
(
reversed
(
data
)))
self
.
assertRaises
(
TypeError
,
reversed
,
{})
# don't allow keyword arguments
# don't allow keyword arguments
self
.
assertRaises
(
TypeError
,
reversed
,
[],
a
=
1
)
self
.
assertRaises
(
TypeError
,
reversed
,
[],
a
=
1
)
...
...
Misc/NEWS.d/next/Core and Builtins/2018-05-23-17-18-02.bpo-33462.gurbpbrhe.rst
0 → 100644
View file @
6531bf63
Make dict and dict views reversible. Patch by Rémi Lapeyre.
Objects/clinic/dictobject.c.h
View file @
6531bf63
...
@@ -103,4 +103,22 @@ dict_setdefault(PyDictObject *self, PyObject *const *args, Py_ssize_t nargs)
...
@@ -103,4 +103,22 @@ dict_setdefault(PyDictObject *self, PyObject *const *args, Py_ssize_t nargs)
exit:
exit:
return
return_value
;
return
return_value
;
}
}
/*[clinic end generated code: output=d7508c5091609a23 input=a9049054013a1b77]*/
PyDoc_STRVAR
(
dict___reversed____doc__
,
"__reversed__($self, /)
\n
"
"--
\n
"
"
\n
"
"Return a reverse iterator over the dict keys."
);
#define DICT___REVERSED___METHODDEF \
{"__reversed__", (PyCFunction)dict___reversed__, METH_NOARGS, dict___reversed____doc__},
static
PyObject
*
dict___reversed___impl
(
PyDictObject
*
self
);
static
PyObject
*
dict___reversed__
(
PyDictObject
*
self
,
PyObject
*
Py_UNUSED
(
ignored
))
{
return
dict___reversed___impl
(
self
);
}
/*[clinic end generated code: output=b9923851cbd9213a input=a9049054013a1b77]*/
Objects/dictobject.c
View file @
6531bf63
...
@@ -3100,6 +3100,7 @@ static PyMethodDef mapp_methods[] = {
...
@@ -3100,6 +3100,7 @@ static PyMethodDef mapp_methods[] = {
clear__doc__
},
clear__doc__
},
{
"copy"
,
(
PyCFunction
)
dict_copy
,
METH_NOARGS
,
{
"copy"
,
(
PyCFunction
)
dict_copy
,
METH_NOARGS
,
copy__doc__
},
copy__doc__
},
DICT___REVERSED___METHODDEF
{
NULL
,
NULL
}
/* sentinel */
{
NULL
,
NULL
}
/* sentinel */
};
};
...
@@ -3335,22 +3336,32 @@ dictiter_new(PyDictObject *dict, PyTypeObject *itertype)
...
@@ -3335,22 +3336,32 @@ dictiter_new(PyDictObject *dict, PyTypeObject *itertype)
{
{
dictiterobject
*
di
;
dictiterobject
*
di
;
di
=
PyObject_GC_New
(
dictiterobject
,
itertype
);
di
=
PyObject_GC_New
(
dictiterobject
,
itertype
);
if
(
di
==
NULL
)
if
(
di
==
NULL
)
{
return
NULL
;
return
NULL
;
}
Py_INCREF
(
dict
);
Py_INCREF
(
dict
);
di
->
di_dict
=
dict
;
di
->
di_dict
=
dict
;
di
->
di_used
=
dict
->
ma_used
;
di
->
di_used
=
dict
->
ma_used
;
di
->
di_pos
=
0
;
di
->
len
=
dict
->
ma_used
;
di
->
len
=
dict
->
ma_used
;
if
(
itertype
==
&
PyDictIterItem_Type
)
{
if
((
itertype
==
&
PyDictRevIterKey_Type
||
itertype
==
&
PyDictRevIterItem_Type
||
itertype
==
&
PyDictRevIterValue_Type
)
&&
dict
->
ma_used
)
{
di
->
di_pos
=
dict
->
ma_keys
->
dk_nentries
-
1
;
}
else
{
di
->
di_pos
=
0
;
}
if
(
itertype
==
&
PyDictIterItem_Type
||
itertype
==
&
PyDictRevIterItem_Type
)
{
di
->
di_result
=
PyTuple_Pack
(
2
,
Py_None
,
Py_None
);
di
->
di_result
=
PyTuple_Pack
(
2
,
Py_None
,
Py_None
);
if
(
di
->
di_result
==
NULL
)
{
if
(
di
->
di_result
==
NULL
)
{
Py_DECREF
(
di
);
Py_DECREF
(
di
);
return
NULL
;
return
NULL
;
}
}
}
}
else
else
{
di
->
di_result
=
NULL
;
di
->
di_result
=
NULL
;
}
_PyObject_GC_TRACK
(
di
);
_PyObject_GC_TRACK
(
di
);
return
(
PyObject
*
)
di
;
return
(
PyObject
*
)
di
;
}
}
...
@@ -3664,6 +3675,120 @@ PyTypeObject PyDictIterItem_Type = {
...
@@ -3664,6 +3675,120 @@ PyTypeObject PyDictIterItem_Type = {
};
};
/* dictreviter */
static
PyObject
*
dictreviter_iternext
(
dictiterobject
*
di
)
{
PyDictObject
*
d
=
di
->
di_dict
;
if
(
d
==
NULL
)
{
return
NULL
;
}
assert
(
PyDict_Check
(
d
));
if
(
di
->
di_used
!=
d
->
ma_used
)
{
PyErr_SetString
(
PyExc_RuntimeError
,
"dictionary changed size during iteration"
);
di
->
di_used
=
-
1
;
/* Make this state sticky */
return
NULL
;
}
Py_ssize_t
i
=
di
->
di_pos
;
PyDictKeysObject
*
k
=
d
->
ma_keys
;
PyObject
*
key
,
*
value
,
*
result
;
if
(
d
->
ma_values
)
{
if
(
i
<
0
)
{
goto
fail
;
}
key
=
DK_ENTRIES
(
k
)[
i
].
me_key
;
value
=
d
->
ma_values
[
i
];
assert
(
value
!=
NULL
);
}
else
{
PyDictKeyEntry
*
entry_ptr
=
&
DK_ENTRIES
(
k
)[
i
];
while
(
i
>=
0
&&
entry_ptr
->
me_value
==
NULL
)
{
entry_ptr
--
;
i
--
;
}
if
(
i
<
0
)
{
goto
fail
;
}
key
=
entry_ptr
->
me_key
;
value
=
entry_ptr
->
me_value
;
}
di
->
di_pos
=
i
-
1
;
di
->
len
--
;
if
(
Py_TYPE
(
di
)
==
&
PyDictRevIterKey_Type
)
{
Py_INCREF
(
key
);
return
key
;
}
else
if
(
Py_TYPE
(
di
)
==
&
PyDictRevIterValue_Type
)
{
Py_INCREF
(
value
);
return
value
;
}
else
if
(
Py_TYPE
(
di
)
==
&
PyDictRevIterItem_Type
)
{
Py_INCREF
(
key
);
Py_INCREF
(
value
);
result
=
di
->
di_result
;
if
(
Py_REFCNT
(
result
)
==
1
)
{
PyObject
*
oldkey
=
PyTuple_GET_ITEM
(
result
,
0
);
PyObject
*
oldvalue
=
PyTuple_GET_ITEM
(
result
,
1
);
PyTuple_SET_ITEM
(
result
,
0
,
key
);
/* steals reference */
PyTuple_SET_ITEM
(
result
,
1
,
value
);
/* steals reference */
Py_INCREF
(
result
);
Py_DECREF
(
oldkey
);
Py_DECREF
(
oldvalue
);
}
else
{
result
=
PyTuple_New
(
2
);
if
(
result
==
NULL
)
{
return
NULL
;
}
PyTuple_SET_ITEM
(
result
,
0
,
key
);
/* steals reference */
PyTuple_SET_ITEM
(
result
,
1
,
value
);
/* steals reference */
}
return
result
;
}
else
{
Py_UNREACHABLE
();
}
fail:
di
->
di_dict
=
NULL
;
Py_DECREF
(
d
);
return
NULL
;
}
PyTypeObject
PyDictRevIterKey_Type
=
{
PyVarObject_HEAD_INIT
(
&
PyType_Type
,
0
)
"dict_reversekeyiterator"
,
sizeof
(
dictiterobject
),
.
tp_dealloc
=
(
destructor
)
dictiter_dealloc
,
.
tp_flags
=
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_HAVE_GC
,
.
tp_traverse
=
(
traverseproc
)
dictiter_traverse
,
.
tp_iter
=
PyObject_SelfIter
,
.
tp_iternext
=
(
iternextfunc
)
dictreviter_iternext
,
.
tp_methods
=
dictiter_methods
};
/*[clinic input]
dict.__reversed__
Return a reverse iterator over the dict keys.
[clinic start generated code]*/
static
PyObject
*
dict___reversed___impl
(
PyDictObject
*
self
)
/*[clinic end generated code: output=e674483336d1ed51 input=23210ef3477d8c4d]*/
{
assert
(
PyDict_Check
(
self
));
return
dictiter_new
(
self
,
&
PyDictRevIterKey_Type
);
}
static
PyObject
*
static
PyObject
*
dictiter_reduce
(
dictiterobject
*
di
,
PyObject
*
Py_UNUSED
(
ignored
))
dictiter_reduce
(
dictiterobject
*
di
,
PyObject
*
Py_UNUSED
(
ignored
))
{
{
...
@@ -3671,7 +3796,6 @@ dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored))
...
@@ -3671,7 +3796,6 @@ dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored))
dictiterobject
tmp
=
*
di
;
dictiterobject
tmp
=
*
di
;
Py_XINCREF
(
tmp
.
di_dict
);
Py_XINCREF
(
tmp
.
di_dict
);
/* iterate the temporary into a list */
PyObject
*
list
=
PySequence_List
((
PyObject
*
)
&
tmp
);
PyObject
*
list
=
PySequence_List
((
PyObject
*
)
&
tmp
);
Py_XDECREF
(
tmp
.
di_dict
);
Py_XDECREF
(
tmp
.
di_dict
);
if
(
list
==
NULL
)
{
if
(
list
==
NULL
)
{
...
@@ -3680,6 +3804,30 @@ dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored))
...
@@ -3680,6 +3804,30 @@ dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored))
return
Py_BuildValue
(
"N(N)"
,
_PyObject_GetBuiltin
(
"iter"
),
list
);
return
Py_BuildValue
(
"N(N)"
,
_PyObject_GetBuiltin
(
"iter"
),
list
);
}
}
PyTypeObject
PyDictRevIterItem_Type
=
{
PyVarObject_HEAD_INIT
(
&
PyType_Type
,
0
)
"dict_reverseitemiterator"
,
sizeof
(
dictiterobject
),
.
tp_dealloc
=
(
destructor
)
dictiter_dealloc
,
.
tp_flags
=
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_HAVE_GC
,
.
tp_traverse
=
(
traverseproc
)
dictiter_traverse
,
.
tp_iter
=
PyObject_SelfIter
,
.
tp_iternext
=
(
iternextfunc
)
dictreviter_iternext
,
.
tp_methods
=
dictiter_methods
};
PyTypeObject
PyDictRevIterValue_Type
=
{
PyVarObject_HEAD_INIT
(
&
PyType_Type
,
0
)
"dict_reversevalueiterator"
,
sizeof
(
dictiterobject
),
.
tp_dealloc
=
(
destructor
)
dictiter_dealloc
,
.
tp_flags
=
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_HAVE_GC
,
.
tp_traverse
=
(
traverseproc
)
dictiter_traverse
,
.
tp_iter
=
PyObject_SelfIter
,
.
tp_iternext
=
(
iternextfunc
)
dictreviter_iternext
,
.
tp_methods
=
dictiter_methods
};
/***********************************************/
/***********************************************/
/* View objects for keys(), items(), values(). */
/* View objects for keys(), items(), values(). */
/***********************************************/
/***********************************************/
...
@@ -4035,9 +4183,16 @@ dictviews_isdisjoint(PyObject *self, PyObject *other)
...
@@ -4035,9 +4183,16 @@ dictviews_isdisjoint(PyObject *self, PyObject *other)
PyDoc_STRVAR
(
isdisjoint_doc
,
PyDoc_STRVAR
(
isdisjoint_doc
,
"Return True if the view and the given iterable have a null intersection."
);
"Return True if the view and the given iterable have a null intersection."
);
static
PyObject
*
dictkeys_reversed
(
_PyDictViewObject
*
dv
);
PyDoc_STRVAR
(
reversed_keys_doc
,
"Return a reverse iterator over the dict keys."
);
static
PyMethodDef
dictkeys_methods
[]
=
{
static
PyMethodDef
dictkeys_methods
[]
=
{
{
"isdisjoint"
,
(
PyCFunction
)
dictviews_isdisjoint
,
METH_O
,
{
"isdisjoint"
,
(
PyCFunction
)
dictviews_isdisjoint
,
METH_O
,
isdisjoint_doc
},
isdisjoint_doc
},
{
"__reversed__"
,
(
PyCFunction
)
dictkeys_reversed
,
METH_NOARGS
,
reversed_keys_doc
},
{
NULL
,
NULL
}
/* sentinel */
{
NULL
,
NULL
}
/* sentinel */
};
};
...
@@ -4080,6 +4235,15 @@ dictkeys_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
...
@@ -4080,6 +4235,15 @@ dictkeys_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
return
_PyDictView_New
(
dict
,
&
PyDictKeys_Type
);
return
_PyDictView_New
(
dict
,
&
PyDictKeys_Type
);
}
}
static
PyObject
*
dictkeys_reversed
(
_PyDictViewObject
*
dv
)
{
if
(
dv
->
dv_dict
==
NULL
)
{
Py_RETURN_NONE
;
}
return
dictiter_new
(
dv
->
dv_dict
,
&
PyDictRevIterKey_Type
);
}
/*** dict_items ***/
/*** dict_items ***/
static
PyObject
*
static
PyObject
*
...
@@ -4125,9 +4289,16 @@ static PySequenceMethods dictitems_as_sequence = {
...
@@ -4125,9 +4289,16 @@ static PySequenceMethods dictitems_as_sequence = {
(
objobjproc
)
dictitems_contains
,
/* sq_contains */
(
objobjproc
)
dictitems_contains
,
/* sq_contains */
};
};
static
PyObject
*
dictitems_reversed
(
_PyDictViewObject
*
dv
);
PyDoc_STRVAR
(
reversed_items_doc
,
"Return a reverse iterator over the dict items."
);
static
PyMethodDef
dictitems_methods
[]
=
{
static
PyMethodDef
dictitems_methods
[]
=
{
{
"isdisjoint"
,
(
PyCFunction
)
dictviews_isdisjoint
,
METH_O
,
{
"isdisjoint"
,
(
PyCFunction
)
dictviews_isdisjoint
,
METH_O
,
isdisjoint_doc
},
isdisjoint_doc
},
{
"__reversed__"
,
(
PyCFunction
)
dictitems_reversed
,
METH_NOARGS
,
reversed_items_doc
},
{
NULL
,
NULL
}
/* sentinel */
{
NULL
,
NULL
}
/* sentinel */
};
};
...
@@ -4170,6 +4341,15 @@ dictitems_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
...
@@ -4170,6 +4341,15 @@ dictitems_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
return
_PyDictView_New
(
dict
,
&
PyDictItems_Type
);
return
_PyDictView_New
(
dict
,
&
PyDictItems_Type
);
}
}
static
PyObject
*
dictitems_reversed
(
_PyDictViewObject
*
dv
)
{
if
(
dv
->
dv_dict
==
NULL
)
{
Py_RETURN_NONE
;
}
return
dictiter_new
(
dv
->
dv_dict
,
&
PyDictRevIterItem_Type
);
}
/*** dict_values ***/
/*** dict_values ***/
static
PyObject
*
static
PyObject
*
...
@@ -4192,7 +4372,14 @@ static PySequenceMethods dictvalues_as_sequence = {
...
@@ -4192,7 +4372,14 @@ static PySequenceMethods dictvalues_as_sequence = {
(
objobjproc
)
0
,
/* sq_contains */
(
objobjproc
)
0
,
/* sq_contains */
};
};
static
PyObject
*
dictvalues_reversed
(
_PyDictViewObject
*
dv
);
PyDoc_STRVAR
(
reversed_values_doc
,
"Return a reverse iterator over the dict values."
);
static
PyMethodDef
dictvalues_methods
[]
=
{
static
PyMethodDef
dictvalues_methods
[]
=
{
{
"__reversed__"
,
(
PyCFunction
)
dictvalues_reversed
,
METH_NOARGS
,
reversed_values_doc
},
{
NULL
,
NULL
}
/* sentinel */
{
NULL
,
NULL
}
/* sentinel */
};
};
...
@@ -4235,6 +4422,16 @@ dictvalues_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
...
@@ -4235,6 +4422,16 @@ dictvalues_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
return
_PyDictView_New
(
dict
,
&
PyDictValues_Type
);
return
_PyDictView_New
(
dict
,
&
PyDictValues_Type
);
}
}
static
PyObject
*
dictvalues_reversed
(
_PyDictViewObject
*
dv
)
{
if
(
dv
->
dv_dict
==
NULL
)
{
Py_RETURN_NONE
;
}
return
dictiter_new
(
dv
->
dv_dict
,
&
PyDictRevIterValue_Type
);
}
/* Returns NULL if cannot allocate a new PyDictKeysObject,
/* Returns NULL if cannot allocate a new PyDictKeysObject,
but does not set an error */
but does not set an error */
PyDictKeysObject
*
PyDictKeysObject
*
...
...
Objects/object.c
View file @
6531bf63
...
@@ -1790,6 +1790,15 @@ _Py_ReadyTypes(void)
...
@@ -1790,6 +1790,15 @@ _Py_ReadyTypes(void)
if
(
PyType_Ready
(
&
PyDictItems_Type
)
<
0
)
if
(
PyType_Ready
(
&
PyDictItems_Type
)
<
0
)
Py_FatalError
(
"Can't initialize dict items type"
);
Py_FatalError
(
"Can't initialize dict items type"
);
if
(
PyType_Ready
(
&
PyDictRevIterKey_Type
)
<
0
)
Py_FatalError
(
"Can't initialize reversed dict keys type"
);
if
(
PyType_Ready
(
&
PyDictRevIterValue_Type
)
<
0
)
Py_FatalError
(
"Can't initialize reversed dict values type"
);
if
(
PyType_Ready
(
&
PyDictRevIterItem_Type
)
<
0
)
Py_FatalError
(
"Can't initialize reversed dict items type"
);
if
(
PyType_Ready
(
&
PyODict_Type
)
<
0
)
if
(
PyType_Ready
(
&
PyODict_Type
)
<
0
)
Py_FatalError
(
"Can't initialize OrderedDict type"
);
Py_FatalError
(
"Can't initialize OrderedDict type"
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment