Python中如何避免函数的副作用

我现在有许多函数,都是这样定义的:

def func1(context):
    context_ = copy(context)
    # do something
    context_.xxx = xxxx
    return context_

因为我不想因为副作用修改传入的参数,所以函数的首行,都 copy 了一下。 觉得这样有些重复,有没有什么方法,比如装饰器,或者 context manager,省去每次显式 copy 的做法?

ps: 我是有许多这样的函数,想创建一个 pipeline,为了简单就入参和出参一样了


Python中如何避免函数的副作用

17 回复

不清楚 copy 是否有用,但是 copy.deepcopy 一定不会错。
装饰器搞得定。


在Python里,要避免函数副作用,核心就是让函数成为“纯函数”——只依赖输入参数,不修改外部状态,并且每次相同输入都返回相同输出。

最直接的方法是:函数内部不修改传入的可变对象(如列表、字典),也不依赖或修改全局变量、类属性等外部状态。

举个例子,下面这个函数有副作用,它直接修改了传入的列表:

def add_to_list(item, target_list):
    target_list.append(item)
    return target_list

my_list = [1, 2, 3]
new_list = add_to_list(4, my_list)
print(my_list)  # 输出 [1, 2, 3, 4] —— 原列表被改了!

要避免这个副作用,函数应该创建并返回一个新列表:

def add_to_list_pure(item, target_list):
    # 创建原列表的副本,避免修改输入
    new_list = target_list.copy()
    new_list.append(item)
    return new_list

my_list = [1, 2, 3]
new_list = add_to_list_pure(4, my_list)
print(my_list)  # 输出 [1, 2, 3] —— 原列表保持不变
print(new_list) # 输出 [1, 2, 3, 4]

对于字典等可变对象也一样,使用.copy()方法或dict()构造函数创建副本。对于嵌套结构,可能需要copy模块的deepcopy

另外,避免使用global关键字在函数内修改全局变量。如果函数需要“记忆”状态,考虑使用闭包或类来显式地管理。

总结:写纯函数,操作副本而非原件。

在调用前复制一下入参不行么?所有的函数调用都不想改入参?需要改入参的情况才是常态吧?

装饰器的典型应用场景…
面向切面了解一下.

避免函数的副作用的正确方法就是不写函数,不写函数就不用传参,不传参就不用担心副作用,不写函数就不用调用,像写作文一样去写

那还怎么维护

维护不是别人的事吗,写完你就该撤了

为什么不写类来表达上下文?
一个对象内部的数据就可以作为上下文

哦,楼主的重点是每次要复制一份新的上下文来用哈

写一个专门的复制函数复制你的 context

用装饰器加复制函数实现预复制功能

!!! 这种思想能写好程序?对自己的代码负责,ok ?

每个函数开头都 copy 一下?浪费了 memory 又拖慢了 performance

封装好 context, 只给特定的代码修改权限呗

因噎废食,熟练掌握语言,知道哪些操作会修改对象哪些不对,在纯函数里不在参数上调用那些会修改对象的函数 /方法就可以了

我觉得你需要的是实现 immutable object,而不是手动 copy

不要故意带歪路。

回到顶部