Python中如何优雅地解决业务代码中重复嵌套检查返回结果是否为None的问题?

在改进学校学长学姐的一些项目,感觉代码结构组织的一团糟,现在又不好做大的修改。

他们的代码一个明显的问题就是很多函数或者方法的调用,如果相关结果不对,就直接返回 None(或者 False)。这样的后果是,等程序真正出了问题的时候,除了一步步 debug我很难找到这个 None 到底是哪个地方返回的

我现在的想法是重新修改代码,在有可能返回 None 的地方,我自己重新检查一遍返回结果是否为 None ,如果返回结果是 None 我自己另外再做处理。但是这样感觉写出的代码太丑陋了,代码里面充满if xxx is None式检查语句。

请问 V 站各位前辈对于上面这种情况我应该如何优雅处理?


Python中如何优雅地解决业务代码中重复嵌套检查返回结果是否为None的问题?

13 回复

这是异常处理?
如果出异常了,需要中断处理,那么就抛异常。
如果出异常了,可以继续执行,那么就忽略异常,一般就返回 None 了。


# 使用装饰器统一处理None检查
def none_check(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        if result is None:
            raise ValueError(f"函数 {func.__name__} 返回了None值")
        return result
    return wrapper

# 使用链式调用处理多层嵌套
class ResultWrapper:
    def __init__(self, value):
        self.value = value
    
    def bind(self, func):
        if self.value is None:
            return ResultWrapper(None)
        try:
            return ResultWrapper(func(self.value))
        except Exception:
            return ResultWrapper(None)
    
    def get_or_default(self, default):
        return self.value if self.value is not None else default

# 使用Optional类型和模式匹配(Python 3.10+)
from typing import Optional

def process_data(data: Optional[dict]) -> Optional[str]:
    match data:
        case None:
            return None
        case {"user": {"profile": {"name": name}}} if name:
            return name.upper()
        case _:
            return None

# 使用Maybe模式简化代码
class Maybe:
    def __init__(self, value):
        self.value = value
    
    def map(self, func):
        return Maybe(func(self.value)) if self.value is not None else Maybe(None)
    
    def get_or_else(self, default):
        return self.value if self.value is not None else default

# 实际使用示例
@none_check
def get_user_data(user_id):
    # 模拟可能返回None的函数
    return {"name": "Alice"} if user_id == 1 else None

# 链式调用示例
result = (ResultWrapper(1)
          .bind(lambda x: x + 1)
          .bind(lambda x: x * 2)
          .get_or_default(0))

# Maybe模式示例
maybe_result = Maybe(5).map(lambda x: x * 2).get_or_else(0)

装饰器适合统一处理函数返回值的None检查,链式调用能优雅处理多层操作,Maybe模式提供了函数式编程的解决方案,模式匹配则让代码更清晰。根据场景选最合适的方案就行。

关键步骤记日志?


他们的代码的本意应该就是出了异常,认为可以忽略异常,然后就返回 None 。但是这样的做法假设有一个函数或者方法,它被嵌套调用了多次,所以在一系列嵌套调用的过程必须每一次都要检查 None ,要不然等出了错就不知道异常到底是哪一步骤抛出来的。

我现在有两种做法:
1. 原本返回 None 的地方我不兼容异常,全部抛出
2. 在返回 None 的地方做检查,并且记录日志,但是这样的话代码结构会很丑

请问上面做法是否合理?

这个问题,我觉得可以等同于:请问 V 站各位前辈不得不吃屎时是如何优雅处理的?

其中的煎熬难以言喻,其路漫漫,其修远兮~

把鼻子堵上,

先为现有的业务逻辑建立一些测试用例,然后再开始修改现有实现,保证前面的测试用例通过,逐步修改

把需要用到的代码封装一下再用

装饰器不就是在这时候用的吗。

1 可以把一些逻辑拆出来。然后写单元测试~
2 抛出异常,捕获异常写日志~~

try catch 就是这个时候用的啊。我一般是喜欢 在关键部分: try: except KeyError xxx except IndexError…

Python 不熟,但 script 类语言应该都可以写一个调用函数的函数解决:_call_func 有 3 个参数,函数名,参数个数,参数对象数组(或集合什么的能放下所有种类对象的)。 用这个函数调用所有的其他函数,在这个函数里面检查返回值,如果是 none ,就抛出异常,或者打印函数名称。 对象方法也可以,重载_call_func 第一个参数是对象,第二个参数是对象的方法,其他一样。然后把所有直接调用都改成调用函数调用。

用日志打印出来吧,出问题 返回 None 之前,先把 当前的函数名打印出来,再返回。

回到顶部