Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
6531bf63
Kaydet (Commit)
6531bf63
authored
Kas 06, 2018
tarafından
Rémi Lapeyre
Kaydeden (comit)
INADA Naoki
Kas 06, 2018
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
bpo-33462: Add __reversed__ to dict and dict views (GH-6827)
üst
16c8a534
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
346 additions
and
24 deletions
+346
-24
stdtypes.rst
Doc/library/stdtypes.rst
+29
-0
3.8.rst
Doc/whatsnew/3.8.rst
+3
-0
dictobject.h
Include/dictobject.h
+3
-0
test_collections.py
Lib/test/test_collections.py
+12
-13
test_dict.py
Lib/test/test_dict.py
+66
-3
test_enumerate.py
Lib/test/test_enumerate.py
+2
-2
2018-05-23-17-18-02.bpo-33462.gurbpbrhe.rst
... and Builtins/2018-05-23-17-18-02.bpo-33462.gurbpbrhe.rst
+1
-0
dictobject.c.h
Objects/clinic/dictobject.c.h
+19
-1
dictobject.c
Objects/dictobject.c
+202
-5
object.c
Objects/object.c
+9
-0
No files found.
Doc/library/stdtypes.rst
Dosyayı görüntüle @
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
Dosyayı görüntüle @
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
Dosyayı görüntüle @
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
Dosyayı görüntüle @
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
,
1
j
,
dict
(),
set
(),
frozenset
()]
non_samples
=
[
None
,
42
,
3.14
,
1
j
,
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
Dosyayı görüntüle @
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
Dosyayı görüntüle @
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
Dosyayı görüntüle @
6531bf63
Make dict and dict views reversible. Patch by Rémi Lapeyre.
Objects/clinic/dictobject.c.h
Dosyayı görüntüle @
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
Dosyayı görüntüle @
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
Dosyayı görüntüle @
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