Skip to content

Commit c889a51

Browse files
committed
Change admonition to rubric; cross-reference glossary
1 parent 87b4111 commit c889a51

File tree

1 file changed

+102
-100
lines changed

1 file changed

+102
-100
lines changed

Doc/library/stdtypes.rst

Lines changed: 102 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -5593,142 +5593,144 @@ can be used interchangeably to index the same dictionary entry.
55935593
of a :class:`dict`.
55945594

55955595

5596-
.. admonition:: Thread safety
5596+
.. _thread-safety-dict:
55975597

5598-
Creating a dictionary with the :class:`dict` constructor is atomic when the
5599-
argument to it is a :class:`dict` or a :class:`tuple`. When using the
5600-
:meth:`dict.fromkeys` method, dictionary creation is atomic when the
5601-
argument is a :class:`dict`, :class:`tuple`, :class:`set` or
5602-
:class:`frozenset`.
5598+
.. rubric:: Thread safety for dict objects
56035599

5604-
The following operations and functions are lock-free and
5605-
:term:`atomic <atomic operation>`.
5600+
Creating a dictionary with the :class:`dict` constructor is atomic when the
5601+
argument to it is a :class:`dict` or a :class:`tuple`. When using the
5602+
:meth:`dict.fromkeys` method, dictionary creation is atomic when the
5603+
argument is a :class:`dict`, :class:`tuple`, :class:`set` or
5604+
:class:`frozenset`.
56065605

5607-
.. code-block::
5608-
:class: good
5606+
The following operations and functions are :term:`lock-free` and
5607+
:term:`atomic <atomic operation>`.
56095608

5610-
d[key] # dict.__getitem__
5611-
d.get(key) # dict.get
5612-
key in d # dict.__contains__
5613-
len(d) # dict.__len__
5609+
.. code-block::
5610+
:class: good
56145611
5615-
All other operations from here on hold the per-object lock.
5612+
d[key] # dict.__getitem__
5613+
d.get(key) # dict.get
5614+
key in d # dict.__contains__
5615+
len(d) # dict.__len__
56165616
5617-
Writing or removing a single item is safe to call from multiple threads
5618-
and will not corrupt the dictionary:
5617+
All other operations from here on hold the :term:`per-object lock`.
56195618

5620-
.. code-block::
5621-
:class: good
5619+
Writing or removing a single item is safe to call from multiple threads
5620+
and will not corrupt the dictionary:
56225621

5623-
d[key] = value # write
5624-
del d[key] # delete
5625-
d.pop(key) # remove and return
5626-
d.popitem() # remove and return last item
5627-
d.setdefault(key, v) # insert if missing
5622+
.. code-block::
5623+
:class: good
56285624
5629-
These operations may compare keys using :meth:`~object.__eq__`, which can
5630-
execute arbitrary Python code. During such comparisons, the dictionary may
5631-
be modified by another thread. For built-in types like :class:`str`,
5632-
:class:`int`, and :class:`float`, that implement :meth:`~object.__eq__` in C,
5633-
the underlying lock is not released during comparisons and this is not a
5634-
concern.
5625+
d[key] = value # write
5626+
del d[key] # delete
5627+
d.pop(key) # remove and return
5628+
d.popitem() # remove and return last item
5629+
d.setdefault(key, v) # insert if missing
56355630
5636-
The following operations return new objects and hold the per-object lock
5637-
for the duration of the operation:
5631+
These operations may compare keys using :meth:`~object.__eq__`, which can
5632+
execute arbitrary Python code. During such comparisons, the dictionary may
5633+
be modified by another thread. For built-in types like :class:`str`,
5634+
:class:`int`, and :class:`float`, that implement :meth:`~object.__eq__` in C,
5635+
the underlying lock is not released during comparisons and this is not a
5636+
concern.
56385637

5639-
.. code-block::
5640-
:class: good
5638+
The following operations return new objects and hold the :term:`per-object lock`
5639+
for the duration of the operation:
56415640

5642-
d.copy() # returns a shallow copy of the dictionary
5643-
d | other # merges two dicts into a new dict
5644-
d.keys() # returns a new dict_keys view object
5645-
d.values() # returns a new dict_values view object
5646-
d.items() # returns a new dict_items view object
5641+
.. code-block::
5642+
:class: good
56475643
5648-
The :meth:`~dict.clear` method holds the lock for its duration. Other
5649-
threads cannot observe elements being removed.
5644+
d.copy() # returns a shallow copy of the dictionary
5645+
d | other # merges two dicts into a new dict
5646+
d.keys() # returns a new dict_keys view object
5647+
d.values() # returns a new dict_values view object
5648+
d.items() # returns a new dict_items view object
56505649
5651-
The following operations lock both dictionaries. For :meth:`~dict.update`
5652-
and ``|=``, this applies only when the other operand is a :class:`dict`
5653-
that uses the standard dict iterator (but not subclasses that override
5654-
iteration). For equality comparison, this applies to :class:`dict` and
5655-
its subclasses:
5650+
The :meth:`~dict.clear` method holds the lock for its duration. Other
5651+
threads cannot observe elements being removed.
56565652

5657-
.. code-block::
5658-
:class: good
5653+
The following operations lock both dictionaries. For :meth:`~dict.update`
5654+
and ``|=``, this applies only when the other operand is a :class:`dict`
5655+
that uses the standard dict iterator (but not subclasses that override
5656+
iteration). For equality comparison, this applies to :class:`dict` and
5657+
its subclasses:
56595658

5660-
d.update(other_dict) # both locked when other_dict is a dict
5661-
d |= other_dict # both locked when other_dict is a dict
5662-
d == other_dict # both locked for dict and subclasses
5659+
.. code-block::
5660+
:class: good
5661+
5662+
d.update(other_dict) # both locked when other_dict is a dict
5663+
d |= other_dict # both locked when other_dict is a dict
5664+
d == other_dict # both locked for dict and subclasses
56635665
5664-
All comparison operations also compare values using :meth:`~object.__eq__`,
5665-
so for non-built-in types the lock may be released during comparison.
5666+
All comparison operations also compare values using :meth:`~object.__eq__`,
5667+
so for non-built-in types the lock may be released during comparison.
56665668

5667-
:meth:`~dict.fromkeys` locks both the new dictionary and the iterable
5668-
when the iterable is exactly a :class:`dict`, :class:`set`, or
5669-
:class:`frozenset` (not subclasses):
5669+
:meth:`~dict.fromkeys` locks both the new dictionary and the iterable
5670+
when the iterable is exactly a :class:`dict`, :class:`set`, or
5671+
:class:`frozenset` (not subclasses):
56705672

5671-
.. code-block::
5672-
:class: good
5673+
.. code-block::
5674+
:class: good
56735675
5674-
dict.fromkeys(a_dict) # locks both
5675-
dict.fromkeys(a_set) # locks both
5676-
dict.fromkeys(a_frozenset) # locks both
5676+
dict.fromkeys(a_dict) # locks both
5677+
dict.fromkeys(a_set) # locks both
5678+
dict.fromkeys(a_frozenset) # locks both
56775679
5678-
When updating from a non-dict iterable, only the target dictionary is
5679-
locked. The iterable may be concurrently modified by another thread:
5680+
When updating from a non-dict iterable, only the target dictionary is
5681+
locked. The iterable may be concurrently modified by another thread:
56805682

5681-
.. code-block::
5682-
:class: maybe
5683+
.. code-block::
5684+
:class: maybe
56835685
5684-
d.update(iterable) # iterable is not a dict: only d locked
5685-
d |= iterable # iterable is not a dict: only d locked
5686-
dict.fromkeys(iterable) # iterable is not a dict/set/frozenset: only result locked
5686+
d.update(iterable) # iterable is not a dict: only d locked
5687+
d |= iterable # iterable is not a dict: only d locked
5688+
dict.fromkeys(iterable) # iterable is not a dict/set/frozenset: only result locked
56875689
5688-
Operations that involve multiple accesses, as well as iteration, are never
5689-
atomic:
5690+
Operations that involve multiple accesses, as well as iteration, are never
5691+
atomic:
56905692

5691-
.. code-block::
5692-
:class: bad
5693+
.. code-block::
5694+
:class: bad
56935695
5694-
# NOT atomic: read-modify-write
5695-
d[key] = d[key] + 1
5696+
# NOT atomic: read-modify-write
5697+
d[key] = d[key] + 1
56965698
5697-
# NOT atomic: check-then-act (TOCTOU)
5698-
if key in d:
5699-
del d[key]
5699+
# NOT atomic: check-then-act (TOCTOU)
5700+
if key in d:
5701+
del d[key]
57005702
5701-
# NOT thread-safe: iteration while modifying
5702-
for key, value in d.items():
5703-
process(key) # another thread may modify d
5703+
# NOT thread-safe: iteration while modifying
5704+
for key, value in d.items():
5705+
process(key) # another thread may modify d
57045706
5705-
To avoid time-of-check to time-of-use (TOCTOU) issues, use atomic
5706-
operations or handle exceptions:
5707+
To avoid time-of-check to time-of-use (TOCTOU) issues, use atomic
5708+
operations or handle exceptions:
57075709

5708-
.. code-block::
5709-
:class: good
5710+
.. code-block::
5711+
:class: good
57105712
5711-
# Use pop() with default instead of check-then-delete
5712-
d.pop(key, None)
5713+
# Use pop() with default instead of check-then-delete
5714+
d.pop(key, None)
57135715
5714-
# Or handle the exception
5715-
try:
5716-
del d[key]
5717-
except KeyError:
5718-
pass
5716+
# Or handle the exception
5717+
try:
5718+
del d[key]
5719+
except KeyError:
5720+
pass
57195721
5720-
To safely iterate over a dictionary that may be modified by another
5721-
thread, iterate over a copy:
5722+
To safely iterate over a dictionary that may be modified by another
5723+
thread, iterate over a copy:
57225724

5723-
.. code-block::
5724-
:class: good
5725+
.. code-block::
5726+
:class: good
57255727
5726-
# Make a copy to iterate safely
5727-
for key, value in d.copy().items():
5728-
process(key)
5728+
# Make a copy to iterate safely
5729+
for key, value in d.copy().items():
5730+
process(key)
57295731
5730-
Consider external synchronization when sharing :class:`dict` instances
5731-
across threads. See :ref:`freethreading-python-howto` for more information.
5732+
Consider external synchronization when sharing :class:`dict` instances
5733+
across threads. See :ref:`freethreading-python-howto` for more information.
57325734

57335735

57345736
.. _dict-views:

0 commit comments

Comments
 (0)