函数是Python的灵魂:lambda、装饰器、闭包

admin 📖 11 分钟阅读

Python的函数和Java有什么不一样?

在Java里,函数必须写在类里面。在Python里,函数是一等公民——可以赋值给变量、作为参数传递、作为返回值。

这个区别决定了Python的编程范式完全不同。

一、基础函数

定义和调用

# Python
def greet(name):
    return f"你好,{name}"

调用

message = greet("张三")

// Java
public String greet(String name) {
    return "你好," + name;
}

默认参数

# Python:直接在参数上设默认值
def greet(name, greeting="你好"):
    return f"{greeting},{name}"

greet("张三") # "你好,张三" greet("张三", "早上好") # "早上好,张三"

// Java 8以前:只能方法重载
// Java没有默认参数,要用重载或者Builder模式
public String greet(String name) {
    return greet(name, "你好");
}
public String greet(String name, String greeting) {
    return greeting + "," + name;
}

可变参数

# Python:*args接收任意数量的参数
def total(*numbers):
    return sum(numbers)

total(1, 2, 3) # 6 total(1, 2, 3, 4, 5) # 15

**kwargs接收任意关键字参数

def print_info(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}")

print_info(name="张三", age=25, city="北京")

// Java的可变参数
public int total(int... numbers) {
    return Arrays.stream(numbers).sum();
}
// 但没有**kwargs这种东西

二、Lambda匿名函数

# Python lambda
add = lambda x, y: x + y
print(add(1, 2))  # 3

常见用法:排序

students = [("张三", 90), ("李四", 85), ("王五", 95)] students.sort(key=lambda s: s[1], reverse=True)

[("王五", 95), ("张三", 90), ("李四", 85)]

常见用法:过滤

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] evens = list(filter(lambda x: x % 2 == 0, numbers))

// Java lambda
BinaryOperator add = (x, y) -> x + y;

// 排序 students.sort(Comparator.comparing(s -> s.score).reversed());

// 过滤 List evens = numbers.stream() .filter(x -> x % 2 == 0) .collect(Collectors.toList());

区别: Python的lambda只能写一行表达式,不能写复杂逻辑。但Python有更强大的替代方案——装饰器和闭包。

三、闭包:Java没有的东西

闭包就是一个函数记住了它被创建时的环境变量

def make_counter(start=0):
    count = [start]  # 用列表包裹,因为int是不可变的
    def counter():
        count[0] += 1
        return count[0]
    return counter

创建计数器

c = make_counter(10) print(c()) # 11 print(c()) # 12 print(c()) # 13

每个计数器独立

c1 = make_counter(0) c2 = make_counter(100) print(c1()) # 1 print(c2()) # 101

Java实现同样功能:

// 需要一个类来保存状态
public class Counter {
    private int count;
    public Counter(int start) { this.count = start; }
    public int next() { return ++count; }
}
// 或者用AtomicInteger + lambda,但远不如Python简洁

闭包的经典用途——柯里化(Currying):

def make_multiplier(n):
    return lambda x: x * n

double = make_multiplier(2) triple = make_multiplier(3)

print(double(5)) # 10 print(triple(5)) # 15

四、装饰器:Python版AOP

装饰器是Python最强大的特性之一。它本质上是一个接受函数、返回函数的高阶函数。

基础装饰器

import time

def timer(func): def wrapper(args, *kwargs): start = time.time() result = func(args, *kwargs) end = time.time() print(f"{func.name} 耗时 {end-start:.2f}秒") return result return wrapper

使用@语法

@timer def slow_function(): time.sleep(1) print("执行完毕")

slow_function()

输出:

执行完毕

slow_function 耗时 1.00秒

Java实现同样功能(AOP):

// 需要Spring AOP或者字节码增强
@Aspect
@Component
public class TimerAspect {
    @Around("execution( com.example..*(..))")
    public Object timer(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = pjp.proceed();
        long end = System.currentTimeMillis();
        System.out.println(pjp.getSignature() + " 耗时 " + (end-start) + "ms");
        return result;
    }
}

Python的装饰器不需要框架,不需要注解处理,一个函数搞定

带参数的装饰器

def retry(max_attempts=3):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_attempts - 1:
                        raise
                    print(f"第{attempt+1}次失败,重试中...")
        return wrapper
    return decorator

@retry(max_attempts=5) def unreliable_api(): import random if random.random() < 0.7: raise Exception("请求失败") return "成功"

这个retry装饰器,Java要写一个注解+一个切面类+一个拦截器,Python 10行搞定。

装饰器的常见用途

# 记忆化(缓存)
from functools import lru_cache

@lru_cache(maxsize=128) def fibonacci(n): if n < 2: return n return fibonacci(n-1) + fibonacci(n-2)

登录验证

def login_required(func): def wrapper(request, args, *kwargs): if not request.user.is_authenticated: return redirect("/login") return func(request, args, *kwargs) return wrapper

@login_required def dashboard(request): return "欢迎来到控制面板"

五、函数式编程工具

# map:对每个元素应用函数
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))

[1, 4, 9, 16, 25]

filter:过滤元素

evens = list(filter(lambda x: x % 2 == 0, numbers))

[2, 4]

reduce:累积计算

from functools import reduce total = reduce(lambda a, b: a + b, numbers) # 15

但更推荐用列表推导式(更Pythonic)

squared = [x**2 for x in numbers] evens = [x for x in numbers if x % 2 == 0]

总结

特性PythonJava
函数作为参数直接传函数式接口
**Python的函数式编程比Java简洁得多,核心原因是函数是"一等公民"。**

下一篇聊Python的面向对象——没有interface、没有private关键字,Python的OOP是怎么玩的?


本系列持续更新中,关注不迷路。

🤖 本文内容由AI辅助整理生成,仅供参考
← 上一篇 Python的数据世界:列表、字典、集合,比Java强太多 下一篇 → 面向对象:Python的类和Java有什么不一样?