You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优雅解决Python多层函数调用中结果传递的冗余问题?

问题描述

我编写了如下代码:

def a():
  d_results = []
  for i in range(10):
    b(i, d_results)
  # do something that needs d_results

def b(i, d_results):
  # do clever b-stuff
  c(d_results)
  # more b-stuff

def c(d_results):
  # do clever c-stuff
  d(d_results)
  # more c-stuff

def d(d_results):
  result = ...
  d_results.append(result)

函数调用链为 a() -> b() -> c() -> d(),d() 生成的结果需要被 a() 收集。目前的做法是在各函数间传递 d_results 列表,但 b() 和 c() 完全不知道这个变量的用途,只是盲目传递,非常不便。

约束条件:

  • 不能使用全局变量,因为这是HTTP请求处理器的一部分,数据需要保持请求本地特性
  • 了解XSLT的隧道参数机制,但Python中没有类似功能

补充背景:d() 会将数据存入GAE数据存储,d_results 是这些操作的Futures对象,为了性能 d() 必须异步执行,所以需要在 a() 中处理这些Futures(因为迭代逻辑在 a() 里)。


可行的优雅解决方案

1. 使用生成器传递结果

让 d() 返回结果,c() 传递 d() 的返回值,b() 传递 c() 的返回值,最终 a() 直接收集 b() 的返回值。中间函数无需关心结果用途,仅需传递返回值:

def a():
  d_results = []
  for i in range(10):
    future = b(i)
    d_results.append(future)
  # 处理d_results

def b(i):
  # do clever b-stuff
  future = c()
  # more b-stuff
  return future

def c():
  # do clever c-stuff
  future = d()
  # more c-stuff
  return future

def d():
  result = ...  # 生成Futures对象
  return result

如果中间函数需要返回自身结果或存在多个结果,可以用生成器 yield 传递:

def a():
  d_results = []
  for i in range(10):
    for future in b(i):
      d_results.append(future)
  # 处理d_results

def b(i):
  # do clever b-stuff
  yield from c()
  # more b-stuff

def c():
  # do clever c-stuff
  yield d()
  # more c-stuff

def d():
  result = ...
  return result

2. 使用上下文管理器实现请求本地存储

通过上下文管理器创建请求专属的存储容器,d() 可直接写入,a() 可直接读取,中间函数无需传递参数:

from contextlib import contextmanager

_request_local = {}

@contextmanager
def request_context():
    global _request_local
    _request_local = {'d_results': []}
    try:
        yield
    finally:
        _request_local.clear()

def a():
    with request_context():
        for i in range(10):
            b(i)
        d_results = _request_local['d_results']
        # 处理d_results

def b(i):
    # do clever b-stuff
    c()
    # more b-stuff

def c():
    # do clever c-stuff
    d()
    # more c-stuff

def d():
    result = ...
    _request_local['d_results'].append(result)

这种方式保证每个请求的 d_results 独立,不会与其他请求混淆,满足请求本地的要求。

3. 使用依赖注入

定义一个结果收集器类,在 a() 中实例化后注入给后续函数,中间函数只需调用收集器接口,无需了解具体实现:

class ResultCollector:
    def __init__(self):
        self.results = []
    
    def add_result(self, result):
        self.results.append(result)

def a():
    collector = ResultCollector()
    for i in range(10):
        b(i, collector)
    d_results = collector.results
    # 处理d_results

def b(i, collector):
    # do clever b-stuff
    c(collector)
    # more b-stuff

def c(collector):
    # do clever c-stuff
    d(collector)
    # more c-stuff

def d(collector):
    result = ...
    collector.add_result(result)

相比直接传递列表,这种方式逻辑更清晰,中间函数明确知道自己在使用收集器,而非盲目传递变量,同时保持了请求本地特性(每个请求实例化新的收集器)。


代码结构思考

当前的调用链本身不存在问题,但传递无意义变量说明中间函数与 d() 的耦合可以优化。上述方法中,生成器和依赖注入更符合Pythonic风格,上下文管理器则适合请求本地场景的全局访问需求。

内容的提问来源于stack exchange,提问作者vicmortelmans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 06:25:21