Python递归树示例

Python递归树示例,python,recursion,Python,Recursion,我正在分析一个Jenkins构建中的一些代码,它使用递归来获取Jenkins的下游作业的URL def get_all_downstream_jobs_urls(ds_jobs: set = None): global JENKINS_JOBS if not ds_jobs: ds_jobs = set(); ds_jobs.update(extract_ds_job_url(get_ds_jobs(BASE_JOB_URL))) temp = d

我正在分析一个Jenkins构建中的一些代码,它使用递归来获取Jenkins的下游作业的URL

def get_all_downstream_jobs_urls(ds_jobs: set = None):
    global JENKINS_JOBS

    if not ds_jobs: 
         ds_jobs = set(); ds_jobs.update(extract_ds_job_url(get_ds_jobs(BASE_JOB_URL)))

    temp = ds_jobs 

    for _ in ds_jobs.copy():
        result = extract_ds_job_url(get_ds_jobs(_)) # <--- jenkins rest api call
        if result: temp.update(result); JENKINS_JOBS.update(temp);
        else: return temp

    return get_all_downstream_jobs_urls(temp)
def get_all_down_jobs_url(ds_jobs:set=None):
全球JENKINS_就业
如果不是ds_作业:
ds_jobs=set();更新(提取任务url(获取任务(基本任务url)))
temp=ds\u作业
对于ds_作业中的u.copy():

result=extract_ds_job_url(get_ds_jobs(_))#如果
extract_ds_job_url(get_ds_jobs(BASE_job_url))
返回一个空集,则永远调用
get_all down_jobs_url(temp)
。这是因为
for
循环不会做任何事情

顶部的测试应检查是否有
None

if ds_jobs is None:
对于
ds\u作业
为空的单独测试应结束递归:

if not ds_jobs:
    # no downstream jobs to process
    return set()
我不能保证其余的逻辑,但代码中肯定有很多样式错误。我将对其进行重构,以至少消除其中一些错误:

  • JENKINS_作业
    永远不会反弹,因此
    global JENKINS_作业
    是冗余和混乱的,应该删除
  • 不清楚函数为什么要更新全局值并返回结果集。它应该做一个或另一个,而不是两个都做
  • 是一个一次性变量。它表示将不使用该值。但在这里,代码确实使用了它。它应该改名为
    job\u url
  • 你真的不应该使用
    在生产代码中。将代码放在单独的行中
  • ds\u jobs=set()
  • temp
    不是一个好的变量名,
    updated
    可能是一个更好的名称。分配时应将其复制,以便
    updated=set(ds_作业)
    ,并且可以从
    for
    循环中删除
    .copy()
    调用
  • 当第一个作业URL没有下游URL时,返回的
    可能也不是您想要的
  • 如果你真的想要一个下游URL的树,递归调用不应该试图传递到目前为止收集的所有作业URL!对于已经检查过的作业URL,很可能会一次又一次地调用jenkins API
以下代码通过使用堆栈来删除递归,并保证只为每个作业URL调用Jenkins API一次:


最后但并非最不重要的一点是,我强烈怀疑使用第三方库(如)会使这一切变得更加简单;Jenkins API可能只允许您在一次调用中查询此信息,但库可能会为您执行此类调用,并为您提供易于解析的Python对象以获取信息。

我在这里看不到任何递归,除非
extract\u ds\u job\u url()
get\u jobs()
进行递归调用。这里缺少的东西太多,根本无法提供帮助;ds_jobs.update(…)
应该是
ds_jobs=set(…)
global JENKINS\u JOBS
行是多余的(函数中没有任何名称重新绑定)。不要对变量名使用
如果您实际使用了该值,
表示您打算忽略该值。如果是URL,请将变量命名为
URL
temp
也不是一个好名字,你应该使用
temp=ds_jobs.copy()
而不是为循环创建副本。udpated,代码。@MartijnPieters,这不是我的代码。请记住这一点—很好的解释和备选代码示例。谢谢
def get_all_downstream_jobs_urls():
    ds_jobs = set()
    stack = [extract_ds_job_url(get_ds_jobs(BASE_JOB_URL))]
    while stack:
        job_url = stack.pop()
        if job_url in ds_jobs:
            # already seen before, skip
            continue
        ds_jobs.add(job_url)
        # add downstream jobs to the stack for further processing
        stack.extend(extract_ds_job_url(get_ds_jobs(job_url)))
    return ds_jobs