graphlib —グラフのような構造で動作する機能
ソースコード: :source: `Lib / graphlib.py`
- class graphlib.TopologicalSorter(graph=None)
ハッシュ可能なノードのグラフをトポロジカルソートする機能を提供します。
トポロジカル順序は、頂点uから頂点vまでのすべての有向エッジu-> vについて、頂点uが頂点vの前に来るような、グラフ内の頂点の線形順序です。 たとえば、グラフの頂点は実行するタスクを表し、エッジはあるタスクを別のタスクの前に実行する必要があるという制約を表す場合があります。 この例では、トポロジカル順序はタスクの有効なシーケンスにすぎません。 グラフに有向非巡回グラフがない場合、つまり有向非巡回グラフである場合にのみ、完全なトポロジカル順序付けが可能です。
オプションの graph 引数を指定する場合は、キーがノードであり、値がグラフ内のそのノードのすべての先行ノード(そのポイントを指すエッジを持つノード)の反復可能である有向非巡回グラフを表すディクショナリである必要があります。キーの値に)。 add()メソッドを使用して、追加のノードをグラフに追加できます。
一般的なケースでは、特定のグラフの並べ替えを実行するために必要な手順は次のとおりです。
オプションの初期グラフを使用して、 TopologicalSorter のインスタンスを作成します。
グラフにノードを追加します。
グラフ上で prepare()を呼び出します。
is_active()は
True
ですが、 get_ready()によって返されたノードを反復処理して処理します。 処理が終了したら、各ノードで done()を呼び出します。
グラフ内のノードをすぐに並べ替えるだけで、並列処理が必要ない場合は、便利なメソッド TopologicalSorter.static_order()を直接使用できます。
>>> graph = {"D": {"B", "C"}, "C": {"A"}, "B": {"A"}} >>> ts = TopologicalSorter(graph) >>> tuple(ts.static_order()) ('A', 'C', 'B', 'D')
このクラスは、ノードの準備ができたときにノードの並列処理を簡単にサポートするように設計されています。 例えば:
topological_sorter = TopologicalSorter() # Add nodes to 'topological_sorter'... topological_sorter.prepare() while topological_sorter.is_active(): for node in topological_sorter.get_ready(): # Worker threads or processes take nodes to work on off the # 'task_queue' queue. task_queue.put(node) # When the work for a node is done, workers put the node in # 'finalized_tasks_queue' so we can get more nodes to work on. # The definition of 'is_active()' guarantees that, at this point, at # least one node has been placed on 'task_queue' that hasn't yet # been passed to 'done()', so this blocking 'get()' must (eventually) # succeed. After calling 'done()', we loop back to call 'get_ready()' # again, so put newly freed nodes on 'task_queue' as soon as # logically possible. node = finalized_tasks_queue.get() topological_sorter.done(node)
- add(node, *predecessors)
新しいノードとその先行ノードをグラフに追加します。 ノードと先行のすべての要素の両方がハッシュ可能である必要があります。
同じノード引数を使用して複数回呼び出された場合、依存関係のセットは、渡されたすべての依存関係の和集合になります。
依存関係のないノードを追加したり(先行は提供されていません)、依存関係を2回提供したりすることができます。 以前に提供されたことがないノードが先行ノードに含まれている場合、それ自体の先行ノードなしでグラフに自動的に追加されます。
prepare()の後に呼び出された場合、 ValueError を発生させます。
- prepare()
グラフを終了としてマークし、グラフのサイクルを確認します。 いずれかのサイクルが検出されると、 CycleError が発生しますが、 get_ready()を使用して、サイクルがさらに進行をブロックするまで、できるだけ多くのノードを取得できます。 この関数の呼び出し後、グラフを変更できないため、 add()を使用してノードを追加することはできません。
- is_active()
さらに進行できる場合は
True
を返し、それ以外の場合はFalse
を返します。 サイクルが解決をブロックせず、 TopologicalSorter.get_ready()によってまだ返されていないノードの準備ができているか、 TopologicalSorter.done( )は、 TopologicalSorter.get_ready()によって返された数よりも少なくなっています。このクラスの
__bool__()
メソッドはこの関数に従うため、次の代わりに次のようになります。if ts.is_active(): ...
簡単に行うことができます:
if ts: ...
以前に prepare()を呼び出さずに呼び出された場合、 ValueError を発生させます。
- done(*nodes)
TopologicalSorter.get_ready()によって返されたノードのセットを処理済みとしてマークし、ノード内の各ノードの後続ノードのブロックを解除して、 TopologicalSorterの呼び出しによって将来返されるようにします。 get_ready()。
nodes 内のいずれかのノードが、このメソッドへの以前の呼び出しによって処理済みとしてすでにマークされている場合、または TopologicalSorter.addを使用してノードがグラフに追加されていない場合、 ValueError を発生させます()、 prepare()を呼び出さずに呼び出された場合、またはノードが get_ready()によってまだ返されていない場合。
- get_ready()
準備ができているすべてのノードを含む
tuple
を返します。 最初は、先行ノードのないすべてのノードを返し、 TopologicalSorter.done()を呼び出してそれらが処理済みとしてマークされると、さらに呼び出すと、すべての先行ノードがすでに処理されているすべての新しいノードが返されます。 これ以上進行できなくなると、空のタプルが返されます。以前に prepare()を呼び出さずに呼び出された場合、 ValueError を発生させます。
- static_order()
トポロジカル順序でノードを反復処理するイテレータオブジェクトを返します。 このメソッドを使用する場合、 prepare()および done()は呼び出さないでください。 この方法は次と同等です。
def static_order(self): self.prepare() while self.is_active(): node_group = self.get_ready() yield from node_group self.done(*node_group)
返される特定の順序は、アイテムがグラフに挿入された特定の順序によって異なる場合があります。 例えば:
>>> ts = TopologicalSorter() >>> ts.add(3, 2, 1) >>> ts.add(1, 0) >>> print([*ts.static_order()]) [2, 0, 1, 3] >>> ts2 = TopologicalSorter() >>> ts2.add(1, 0) >>> ts2.add(3, 2, 1) >>> print([*ts2.static_order()]) [0, 2, 1, 3]
これは、「0」と「2」がグラフの同じレベルにあり( get_ready()への同じ呼び出しで返される)、それらの間の順序が決定されるためです。挿入順に。
いずれかのサイクルが検出されると、 CycleError が発生します。
バージョン3.9の新機能。
例外
graphlib モジュールは、次の例外クラスを定義します。
- exception graphlib.CycleError
作業グラフにサイクルが存在する場合、 TopologicalSorter.prepare()によって発生する ValueError のサブクラス。 複数のサイクルが存在する場合、それらの中から1つの未定義の選択肢のみが報告され、例外に含まれます。
検出されたサイクルは、例外インスタンスの
args
属性の2番目の要素を介してアクセスでき、ノードのリストで構成されます。グラフでは、各ノードは、グラフ内の次のノードの直前のノードになります。リスト。 報告されたリストでは、最初と最後のノードが同じになり、循環していることが明確になります。