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]
总结
| 特性 | Python | Java |
|---|---|---|
| 函数作为参数 | 直接传 | 函数式接口 |
下一篇聊Python的面向对象——没有interface、没有private关键字,Python的OOP是怎么玩的?
本系列持续更新中,关注不迷路。