gpt4 book ai didi

python - 检测python中的循环依赖

转载 作者:行者123 更新时间:2023-11-28 17:52:32 46 4
gpt4 key购买 nike

我不明白为什么DepsTree类中的_ResolveDependencies方法可以检测到循环依赖。似乎它可以检测到 a 需要 be 并且 b 需要 e,但这不是循环依赖。

class DepsTree(object):
"""Represents the set of dependencies between source files."""

def __init__(self, sources):
"""Initializes the tree with a set of sources.

Args:
sources: A set of JavaScript sources.

Raises:
MultipleProvideError: A namespace is provided by muplitple sources.
NamespaceNotFoundError: A namespace is required but never provided.
"""

self._sources = sources
self._provides_map = dict()

# Ensure nothing was provided twice.
for source in sources:
for provide in source.provides:
if provide in self._provides_map:
raise MultipleProvideError(
provide, [self._provides_map[provide], source])

self._provides_map[provide] = source

# Check that all required namespaces are provided.
for source in sources:
for require in source.requires:
if require not in self._provides_map:
raise NamespaceNotFoundError(require, source)

def GetDependencies(self, required_namespaces):
"""Get source dependencies, in order, for the given namespaces.

Args:
required_namespaces: A string (for one) or list (for one or more) of
namespaces.

Returns:
A list of source objects that provide those namespaces and all
requirements, in dependency order.

Raises:
NamespaceNotFoundError: A namespace is requested but doesn't exist.
CircularDependencyError: A cycle is detected in the dependency tree.
"""
if type(required_namespaces) is str:
required_namespaces = [required_namespaces]

deps_sources = []

for namespace in required_namespaces:
for source in DepsTree._ResolveDependencies(
namespace, [], self._provides_map, []):
if source not in deps_sources:
deps_sources.append(source)

return deps_sources

@staticmethod
def _ResolveDependencies(required_namespace, deps_list, provides_map,
traversal_path):
"""Resolve dependencies for Closure source files.

Follows the dependency tree down and builds a list of sources in dependency
order. This function will recursively call itself to fill all dependencies
below the requested namespaces, and then append its sources at the end of
the list.

Args:
required_namespace: String of required namespace.
deps_list: List of sources in dependency order. This function will append
the required source once all of its dependencies are satisfied.
provides_map: Map from namespace to source that provides it.
traversal_path: List of namespaces of our path from the root down the
dependency/recursion tree. Used to identify cyclical dependencies.
This is a list used as a stack -- when the function is entered, the
current namespace is pushed and popped right before returning.
Each recursive call will check that the current namespace does not
appear in the list, throwing a CircularDependencyError if it does.

Returns:
The given deps_list object filled with sources in dependency order.

Raises:
NamespaceNotFoundError: A namespace is requested but doesn't exist.
CircularDependencyError: A cycle is detected in the dependency tree.
"""

source = provides_map.get(required_namespace)
if not source:
raise NamespaceNotFoundError(required_namespace)

if required_namespace in traversal_path:
traversal_path.append(required_namespace) # do this *after* the test

# This must be a cycle.
raise CircularDependencyError(traversal_path)

traversal_path.append(required_namespace)

for require in source.requires:

# Append all other dependencies before we append our own.
DepsTree._ResolveDependencies(require, deps_list, provides_map,
traversal_path)
deps_list.append(source)

traversal_path.pop()

return deps_list

最佳答案

简短版:_ResolveDependencies 对依赖树进行深度优先遍历,记录路径。如果它遇到一个已经在路径中的节点,这意味着有一个循环。

_ResolveDependencies 遍历 Source.requires 体现的依赖林。在任何时间点对 _ResolveDependencies 的主动调用对应于通过依赖树的路径(因此 traversal_path 中的 _path);这是通过在递归之前将命名空间添加到 traversal_path 并在递归之后将其删除来跟踪的。换句话说,当且仅当 _ResolveDependencies 的调用正在处理命名空间时,命名空间位于 traversal_path 中。如果要求 _ResolveDependencies 检查已存在于 traversal_path 中的命名空间,则对 _ResolveDependencies 的不同调用正在处理命名空间,并且存在从节点到自身的路径,因此是一个循环。

例如,考虑最简单的依赖循环:“a”需要“c”需要“a”。让我们也抛出一个“a”需要“b”来显示当分支中没有依赖项时会发生什么。您将获得以下调用序列(在伪 python 中)。大多数情况下,变量的值被替换为变量名(例如,a 替换为 ns.name)。注意:这并不代表源代码,而是程序运行时执行的语句序列。

_RD(ns={name:a, req: [b, c]}, path=[]):  if a in path: # false  path += [a]  for each subns in [b,c]:    _RD(ns={name: b, req: []}, path=[a]):      if b in path: # false      path += [b]      for each subns in []:      # done with this branch      path -= [b]          _RD(ns={name: c, req: [a]}, path=[a]):      if c in path: # false      path += [c]      for each subns in [a]:        _RD(ns={name: a req: [b,c]}, path=[a, c]):          if a in path: # true            throw CircularDependencyError

关于python - 检测python中的循环依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6974708/

46 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com