mirror of
https://github.com/python/cpython.git
synced 2025-07-24 03:35:53 +00:00
bpo-17005: Minor improvements to the documentation of TopologicalSorter (GH-18155)
This commit is contained in:
parent
7142df5ea2
commit
65ecc390c1
1 changed files with 64 additions and 72 deletions
|
@ -522,54 +522,46 @@ The :mod:`functools` module defines the following functions:
|
||||||
|
|
||||||
Provides functionality to topologically sort a graph of hashable nodes.
|
Provides functionality to topologically sort a graph of hashable nodes.
|
||||||
|
|
||||||
A topological order is a linear ordering of the vertices in a graph such that for
|
A topological order is a linear ordering of the vertices in a graph such that
|
||||||
every directed edge u -> v from vertex u to vertex v, vertex u comes before vertex
|
for every directed edge u -> v from vertex u to vertex v, vertex u comes
|
||||||
v in the ordering. For instance, the vertices of the graph may represent tasks to
|
before vertex v in the ordering. For instance, the vertices of the graph may
|
||||||
be performed, and the edges may represent constraints that one task must be
|
represent tasks to be performed, and the edges may represent constraints that
|
||||||
performed before another; in this example, a topological ordering is just a valid
|
one task must be performed before another; in this example, a topological
|
||||||
sequence for the tasks. A complete topological ordering is possible if and only if
|
ordering is just a valid sequence for the tasks. A complete topological
|
||||||
the graph has no directed cycles, that is, if it is a directed acyclic graph.
|
ordering is possible if and only if the graph has no directed cycles, that
|
||||||
|
is, if it is a directed acyclic graph.
|
||||||
|
|
||||||
If the optional *graph* argument is provided it must be a dictionary representing
|
If the optional *graph* argument is provided it must be a dictionary
|
||||||
a directed acyclic graph where the keys are nodes and the values are iterables of
|
representing a directed acyclic graph where the keys are nodes and the values
|
||||||
all predecessors of that node in the graph (the nodes that have edges that point
|
are iterables of all predecessors of that node in the graph (the nodes that
|
||||||
to the value in the key). Additional nodes can be added to the graph using the
|
have edges that point to the value in the key). Additional nodes can be added
|
||||||
:meth:`~TopologicalSorter.add` method.
|
to the graph using the :meth:`~TopologicalSorter.add` method.
|
||||||
|
|
||||||
In the general case, the steps required to perform the sorting of a given graph
|
In the general case, the steps required to perform the sorting of a given
|
||||||
are as follows:
|
graph are as follows:
|
||||||
|
|
||||||
* Create an instance of the :class:`TopologicalSorter` with an optional initial graph.
|
* Create an instance of the :class:`TopologicalSorter` with an optional
|
||||||
|
initial graph.
|
||||||
* Add additional nodes to the graph.
|
* Add additional nodes to the graph.
|
||||||
* Call :meth:`~TopologicalSorter.prepare` on the graph.
|
* Call :meth:`~TopologicalSorter.prepare` on the graph.
|
||||||
* While :meth:`~TopologicalSorter.is_active` is ``True``, iterate over the
|
* While :meth:`~TopologicalSorter.is_active` is ``True``, iterate over
|
||||||
nodes returned by :meth:`~TopologicalSorter.get_ready` and process them.
|
the nodes returned by :meth:`~TopologicalSorter.get_ready` and
|
||||||
Call :meth:`~TopologicalSorter.done` on each node as it finishes processing.
|
process them. Call :meth:`~TopologicalSorter.done` on each node as it
|
||||||
|
finishes processing.
|
||||||
|
|
||||||
In case just an immediate sorting of the nodes in the graph is required and
|
In case just an immediate sorting of the nodes in the graph is required and
|
||||||
no parallelism is involved, the convenience method :meth:`TopologicalSorter.static_order`
|
no parallelism is involved, the convenience method
|
||||||
can be used directly. For example, this method can be used to implement a simple
|
:meth:`TopologicalSorter.static_order` can be used directly:
|
||||||
version of the C3 linearization algorithm used by Python to calculate the Method
|
|
||||||
Resolution Order (MRO) of a derived class:
|
|
||||||
|
|
||||||
.. doctest::
|
.. doctest::
|
||||||
|
|
||||||
>>> class A: pass
|
>>> graph = {"D": {"B", "C"}, "C": {"A"}, "B": {"A"}}
|
||||||
>>> class B(A): pass
|
|
||||||
>>> class C(A): pass
|
|
||||||
>>> class D(B, C): pass
|
|
||||||
|
|
||||||
>>> D.__mro__
|
|
||||||
(<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
|
|
||||||
|
|
||||||
>>> graph = {D: {B, C}, C: {A}, B: {A}, A:{object}}
|
|
||||||
>>> ts = TopologicalSorter(graph)
|
>>> ts = TopologicalSorter(graph)
|
||||||
>>> topological_order = tuple(ts.static_order())
|
>>> tuple(ts.static_order())
|
||||||
>>> tuple(reversed(topological_order))
|
('A', 'C', 'B', 'D')
|
||||||
(<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
|
|
||||||
|
|
||||||
The class is designed to easily support parallel processing of the nodes as they
|
The class is designed to easily support parallel processing of the nodes as
|
||||||
become ready. For instance::
|
they become ready. For instance::
|
||||||
|
|
||||||
topological_sorter = TopologicalSorter()
|
topological_sorter = TopologicalSorter()
|
||||||
|
|
||||||
|
@ -595,39 +587,39 @@ The :mod:`functools` module defines the following functions:
|
||||||
|
|
||||||
.. method:: add(node, *predecessors)
|
.. method:: add(node, *predecessors)
|
||||||
|
|
||||||
Add a new node and its predecessors to the graph. Both the *node* and
|
Add a new node and its predecessors to the graph. Both the *node* and all
|
||||||
all elements in *predecessors* must be hashable.
|
elements in *predecessors* must be hashable.
|
||||||
|
|
||||||
If called multiple times with the same node argument, the set of dependencies
|
If called multiple times with the same node argument, the set of
|
||||||
will be the union of all dependencies passed in.
|
dependencies will be the union of all dependencies passed in.
|
||||||
|
|
||||||
It is possible to add a node with no dependencies (*predecessors* is not
|
It is possible to add a node with no dependencies (*predecessors* is not
|
||||||
provided) or to provide a dependency twice. If a node that has not been
|
provided) or to provide a dependency twice. If a node that has not been
|
||||||
provided before is included among *predecessors* it will be automatically added
|
provided before is included among *predecessors* it will be automatically
|
||||||
to the graph with no predecessors of its own.
|
added to the graph with no predecessors of its own.
|
||||||
|
|
||||||
Raises :exc:`ValueError` if called after :meth:`~TopologicalSorter.prepare`.
|
Raises :exc:`ValueError` if called after :meth:`~TopologicalSorter.prepare`.
|
||||||
|
|
||||||
.. method:: prepare()
|
.. method:: prepare()
|
||||||
|
|
||||||
Mark the graph as finished and check for cycles in the graph. If any cycle is
|
Mark the graph as finished and check for cycles in the graph. If any cycle
|
||||||
detected, :exc:`CycleError` will be raised, but
|
is detected, :exc:`CycleError` will be raised, but
|
||||||
:meth:`~TopologicalSorter.get_ready` can still be used to obtain as many nodes
|
:meth:`~TopologicalSorter.get_ready` can still be used to obtain as many
|
||||||
as possible until cycles block more progress. After a call to this function,
|
nodes as possible until cycles block more progress. After a call to this
|
||||||
the graph cannot be modified, and therefore no more nodes can be added using
|
function, the graph cannot be modified, and therefore no more nodes can be
|
||||||
:meth:`~TopologicalSorter.add`.
|
added using :meth:`~TopologicalSorter.add`.
|
||||||
|
|
||||||
.. method:: is_active()
|
.. method:: is_active()
|
||||||
|
|
||||||
Returns ``True`` if more progress can be made and ``False`` otherwise. Progress
|
Returns ``True`` if more progress can be made and ``False`` otherwise.
|
||||||
can be made if cycles do not block the resolution and either there are still
|
Progress can be made if cycles do not block the resolution and either
|
||||||
nodes ready that haven't yet been returned by
|
there are still nodes ready that haven't yet been returned by
|
||||||
:meth:`TopologicalSorter.get_ready` or the number of nodes marked
|
:meth:`TopologicalSorter.get_ready` or the number of nodes marked
|
||||||
:meth:`TopologicalSorter.done` is less than the number that have been returned
|
:meth:`TopologicalSorter.done` is less than the number that have been
|
||||||
by :meth:`TopologicalSorter.get_ready`.
|
returned by :meth:`TopologicalSorter.get_ready`.
|
||||||
|
|
||||||
The :meth:`~TopologicalSorter.__bool__` method of this class defers to this
|
The :meth:`~TopologicalSorter.__bool__` method of this class defers to
|
||||||
function, so instead of::
|
this function, so instead of::
|
||||||
|
|
||||||
if ts.is_active():
|
if ts.is_active():
|
||||||
...
|
...
|
||||||
|
@ -637,29 +629,28 @@ The :mod:`functools` module defines the following functions:
|
||||||
if ts:
|
if ts:
|
||||||
...
|
...
|
||||||
|
|
||||||
Raises :exc:`ValueError` if called without calling :meth:`~TopologicalSorter.prepare`
|
Raises :exc:`ValueError` if called without calling
|
||||||
previously.
|
:meth:`~TopologicalSorter.prepare` previously.
|
||||||
|
|
||||||
.. method:: done(*nodes)
|
.. method:: done(*nodes)
|
||||||
|
|
||||||
Marks a set of nodes returned by :meth:`TopologicalSorter.get_ready` as
|
Marks a set of nodes returned by :meth:`TopologicalSorter.get_ready` as
|
||||||
processed, unblocking any successor of each node in *nodes* for being returned
|
processed, unblocking any successor of each node in *nodes* for being
|
||||||
in the future by a call to :meth:`TopologicalSorter.get_ready`.
|
returned in the future by a call to :meth:`TopologicalSorter.get_ready`.
|
||||||
|
|
||||||
Raises :exc:`ValueError` if any node in *nodes* has already been marked as
|
Raises :exc:`ValueError` if any node in *nodes* has already been marked as
|
||||||
processed by a previous call to this method or if a node was not added to the
|
processed by a previous call to this method or if a node was not added to
|
||||||
graph by using :meth:`TopologicalSorter.add`, if called without calling
|
the graph by using :meth:`TopologicalSorter.add`, if called without
|
||||||
:meth:`~TopologicalSorter.prepare` or if node has not yet been returned by
|
calling :meth:`~TopologicalSorter.prepare` or if node has not yet been
|
||||||
:meth:`~TopologicalSorter.get_ready`.
|
returned by :meth:`~TopologicalSorter.get_ready`.
|
||||||
|
|
||||||
.. method:: get_ready()
|
.. method:: get_ready()
|
||||||
|
|
||||||
Returns a ``tuple`` with all the nodes that are ready. Initially it returns all
|
Returns a ``tuple`` with all the nodes that are ready. Initially it
|
||||||
nodes with no predecessors, and once those are marked as processed by calling
|
returns all nodes with no predecessors, and once those are marked as
|
||||||
:meth:`TopologicalSorter.done`, further calls will return all new nodes that
|
processed by calling :meth:`TopologicalSorter.done`, further calls will
|
||||||
have all their predecessors already processed. Once no more progress can be
|
return all new nodes that have all their predecessors already processed.
|
||||||
made, empty tuples are returned.
|
Once no more progress can be made, empty tuples are returned.
|
||||||
made.
|
|
||||||
|
|
||||||
Raises :exc:`ValueError` if called without calling
|
Raises :exc:`ValueError` if called without calling
|
||||||
:meth:`~TopologicalSorter.prepare` previously.
|
:meth:`~TopologicalSorter.prepare` previously.
|
||||||
|
@ -694,9 +685,10 @@ The :mod:`functools` module defines the following functions:
|
||||||
>>> print([*ts2.static_order()])
|
>>> print([*ts2.static_order()])
|
||||||
[0, 2, 1, 3]
|
[0, 2, 1, 3]
|
||||||
|
|
||||||
This is due to the fact that "0" and "2" are in the same level in the graph (they
|
This is due to the fact that "0" and "2" are in the same level in the
|
||||||
would have been returned in the same call to :meth:`~TopologicalSorter.get_ready`)
|
graph (they would have been returned in the same call to
|
||||||
and the order between them is determined by the order of insertion.
|
:meth:`~TopologicalSorter.get_ready`) and the order between them is
|
||||||
|
determined by the order of insertion.
|
||||||
|
|
||||||
|
|
||||||
If any cycle is detected, :exc:`CycleError` will be raised.
|
If any cycle is detected, :exc:`CycleError` will be raised.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue