纯函数是函数式编程Functional Programming的核心概念,它保证了可预测性、可复现性、可组合性等特性。

特性描述
确定性(Deterministic)相同输入始终返回相同输出
无副作用(No Side Effects)不能修改全局变量、文件、数据库等外部状态
引用透明性(Referential Transparency)可以用计算结果替换函数调用,不影响程序逻辑
不依赖外部状态(No External State Dependency)只能依赖函数参数,不能依赖外部变量
不可变性(Immutability)不能修改输入参数
可缓存性(Cacheability)由于相同输入必定产生相同输出,计算结果可以被缓存
易于并行化(Parallelism-Friendly)由于无共享状态,可以在多线程环境中安全执行
可组合性(Composability)纯函数可以组合成更复杂的函数,增强代码复用性
易于测试(Testability)由于不依赖外部状态,测试更简单

1. 确定性(Deterministic)

定义:纯函数的输出完全由输入决定,只要输入相同,输出一定相同。

示例(纯函数 ✅)

def add(x, y):
    return x + y
 
print(add(2, 3))  # 始终返回 5
  • add(2,3) 无论何时调用,都会返回 5,这是纯函数。

示例(非纯函数 ❌)

import random
 
def add_random(x):
    return x + random.randint(1, 10)
 
print(add_random(2))  # 每次运行都可能返回不同的结果
  • random.randint(1, 10) 使得 add_random(2) 的返回值不确定,因此不是纯函数

2. 无副作用(No Side Effects)

定义:纯函数不能修改外部状态,如全局变量、文件、数据库等。

示例(纯函数 ✅)

def square(x):
    return x * x
  • 这个函数不会修改外部变量、不会打印日志、不会写入文件,因此是纯函数。

示例(非纯函数 ❌)

total = 0
 
def add_to_total(x):
    global total
    total += x  # 修改了全局变量
    return total
  • 这个函数修改了全局变量 total,所以它不是纯函数。

3. 参考透明性(Referential Transparency)

定义:如果一个函数调用可以用它的计算结果替换,而不影响程序行为,那么它是引用透明的。

示例(纯函数 ✅)

def multiply(x, y):
    return x * y
 
z = multiply(3, 4)  # 可以用 `12` 直接替换
  • multiply(3, 4) 可以直接替换成 12,不会影响程序逻辑,因此是纯函数。

示例(非纯函数 ❌)

import time
 
def get_time():
    return time.time()
 
t = get_time()  # 不能直接替换成某个固定值,因为每次都会变
  • get_time() 返回的时间每次都不同,因此不是引用透明的

4. 不依赖外部状态(No External State Dependency)

定义:纯函数的结果不能依赖函数外部的变量状态。

示例(纯函数 ✅)

def add(x, y):
    return x + y
  • 该函数仅依赖输入参数 xy,所以是纯函数。

示例(非纯函数 ❌)

factor = 2
 
def multiply(x):
    return x * factor  # 依赖外部变量 `factor`
  • 这个函数依赖外部变量 factor,如果 factor 变化,函数的结果也会变,因此不是纯函数。

5. 不可变性(Immutability)

定义:纯函数不能修改输入参数

示例(纯函数 ✅)

def add_to_list(lst, x):
    return lst + [x]  # 创建新列表,不修改原列表
  • 这个函数不会修改原始 lst,而是返回一个新列表,因此是纯函数。

示例(非纯函数 ❌)

def add_to_list_in_place(lst, x):
    lst.append(x)  # 直接修改了输入参数 `lst`
    return lst
  • lst.append(x) 修改了原始列表 lst,因此不是纯函数。

6. 可缓存性(Cacheability)

定义:由于纯函数相同输入总是得到相同输出,所以可以缓存其结果,提高性能。

示例

from functools import lru_cache
 
@lru_cache(maxsize=100)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)
  • 由于 fib(n) 每次相同输入都会得到相同输出,可以用 @lru_cache 进行缓存,提高计算效率。

7. 易于并行化(Parallelism-Friendly)

定义:纯函数不共享状态,因此可以并行执行,而不会发生数据竞争。

示例

from multiprocessing import Pool
 
def square(x):
    return x * x  # 纯函数
 
with Pool(4) as p:
    print(p.map(square, [1, 2, 3, 4, 5]))
  • square(x) 不会修改任何共享状态,所以可以安全地在多个进程中执行,提高计算效率。

8. 可组合性(Composability)

定义:多个纯函数可以组合成更复杂的函数,增强代码复用性。

示例

def add(x, y):
    return x + y
 
def square(x):
    return x * x
 
result = square(add(2, 3))  # (2 + 3)² = 25
  • add(2, 3) 的输出可以直接作为 square() 的输入,组合性极强。

9. 易于测试(Testability)

定义:纯函数仅依赖输入参数,不依赖外部状态,测试时无需考虑外部环境

示例

def multiply(x, y):
    return x * y
 
# 纯函数可以直接测试
assert multiply(2, 3) == 6
assert multiply(5, 0) == 0
  • 由于 multiply(x, y) 不依赖全局变量、文件、数据库,测试时只需检查输入输出关系,测试更简单。

总结

纯函数是确定性、无副作用、可复现、易测试的核心计算单位,广泛应用于函数式编程(如 Haskell)、数据处理(如 Spark)、并行计算(如 MapReduce),也是 Nix 等技术实现可复现性的关键概念。