第5章:函数与方法
作为 Java 开发者,你已经熟悉了 Java 的方法定义和调用。Python 的函数与 Java 的方法有很多相似之处,但也有一些重要的区别。本章将详细对比两种语言的函数与方法。
5.1 函数定义
Java 方法定义
// 实例方法
public returnType methodName(parameterType parameterName) {
// 方法体
return returnValue;
}
// 静态方法
public static returnType methodName(parameterType parameterName) {
// 方法体
return returnValue;
}
Python 函数定义
def function_name(parameter_name):
"""函数文档字符串"""
# 函数体
return return_value
对比:
| 特性 | Java | Python |
|---|---|---|
| 定义关键字 | public, private, protected, static 等 | def |
| 参数类型 | 必须声明类型 | 无需声明类型(动态类型) |
| 返回类型 | 必须声明类型 | 无需声明类型 |
| 访问修饰符 | 有(public, private, protected) | 无(通过命名约定) |
| 方法体 | 大括号包围 | 缩进 |
| 文档 | Javadoc | 文档字符串(docstring) |
Python 函数示例:
# 基本函数
def greet(name):
"""问候函数"""
return f"Hello, {name}!"
print(greet("Alice")) # Hello, Alice!
# 带默认参数的函数
def greet(name, greeting="Hello"):
"""带默认参数的问候函数"""
return f"{greeting}, {name}!"
print(greet("Bob")) # Hello, Bob!
print(greet("Charlie", "Hi")) # Hi, Charlie!
# 带可变参数的函数
def sum_numbers(*args):
"""计算任意数量数字的和"""
return sum(args)
print(sum_numbers(1, 2, 3, 4, 5)) # 15
# 带关键字参数的函数
def print_person(**kwargs):
"""打印个人信息"""
for key, value in kwargs.items():
print(f"{key}: {value}")
print_person(name="Alice", age=25, city="New York")
5.2 参数传递
Java 参数传递
- 基本类型:值传递
- 引用类型:引用传递
Python 参数传递
- 所有参数:引用传递
- 不可变类型(int, str, tuple):类似值传递
- 可变类型(list, dict, set):类似引用传递
对比示例:
| 操作 | Java | Python |
|---|---|---|
| 传递基本类型 | 值传递 | 引用传递(但不可变) |
| 传递引用类型 | 引用传递 | 引用传递 |
| 修改参数 | 基本类型不影响原值 | 不可变类型不影响原值,可变类型影响原值 |
Python 参数传递示例:
# 不可变类型参数
def modify_integer(x):
x = x + 1
print(f"Inside function: x = {x}")
a = 5
modify_integer(a)
print(f"Outside function: a = {a}") # a 仍然是 5
# 可变类型参数
def modify_list(lst):
lst.append(4)
print(f"Inside function: lst = {lst}")
b = [1, 2, 3]
modify_list(b)
print(f"Outside function: b = {b}") # b 变成了 [1, 2, 3, 4]
# 关键字参数
def person_info(name, age):
return f"Name: {name}, Age: {age}"
# 位置参数
print(person_info("Alice", 25)) # Name: Alice, Age: 25
# 关键字参数
print(person_info(name="Bob", age=30)) # Name: Bob, Age: 30
print(person_info(age=35, name="Charlie")) # Name: Charlie, Age: 35
# 混合使用
print(person_info("David", age=40)) # Name: David, Age: 40
5.3 函数返回值
Java 返回值
- 必须声明返回类型
- 可以返回基本类型或引用类型
void表示无返回值
Python 返回值
- 无需声明返回类型
- 可以返回任意类型
- 未显式返回时,默认返回
None - 可以返回多个值(作为元组)
对比示例:
| 操作 | Java | Python |
|---|---|---|
| 无返回值 | void 方法 | 函数默认返回 None |
| 单个返回值 | 直接返回 | 直接返回 |
| 多个返回值 | 返回对象或数组 | 直接返回多个值(元组) |
Python 返回值示例:
# 无返回值
def print_hello():
print("Hello")
result = print_hello()
print(result) # None
# 单个返回值
def add(a, b):
return a + b
result = add(3, 5)
print(result) # 8
# 多个返回值
def calculate(a, b):
return a + b, a - b, a * b, a / b
add_result, sub_result, mul_result, div_result = calculate(10, 5)
print(add_result, sub_result, mul_result, div_result) # 15 5 50 2.0
# 返回值作为元组
result = calculate(8, 4)
print(result) # (12, 4, 32, 2.0)
print(type(result)) # <class 'tuple'>
5.4 Lambda 表达式
Java Lambda 表达式
// Java 8+
Runnable runnable = () -> System.out.println("Hello");
Function<Integer, Integer> square = x -> x * x;
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.sort((a, b) -> a.compareTo(b));
Python Lambda 表达式
# Python lambda
greet = lambda name: f"Hello, {name}!"
print(greet("Alice")) # Hello, Alice!
square = lambda x: x * x
print(square(5)) # 25
# 作为函数参数
numbers = [3, 1, 4, 1, 5, 9]
numbers.sort(key=lambda x: x)
print(numbers) # [1, 1, 3, 4, 5, 9]
# 与内置函数配合
numbers = [1, 2, 3, 4, 5]
doubled = list(map(lambda x: x * 2, numbers))
print(doubled) # [2, 4, 6, 8, 10]
filtered = list(filter(lambda x: x % 2 == 0, numbers))
print(filtered) # [2, 4]
对比:
| 特性 | Java | Python |
|---|---|---|
| 语法 | (parameters) -> expression | lambda parameters: expression |
| 用途 | 函数式接口实现 | 匿名函数,常用于函数参数 |
| 复杂度 | 可以包含代码块 | 只能是表达式 |
| 类型推断 | 编译器推断 | 动态类型 |
5.5 函数作为对象
Java 函数作为对象
- Java 8+ 引入了函数式接口
- 使用
Function,Consumer,Supplier等 - 方法引用
Python 函数作为对象
- 函数是一等公民
- 可以赋值给变量
- 可以作为参数传递
- 可以作为返回值
- 可以存储在数据结构中
对比示例:
| 操作 | Java | Python |
|---|---|---|
| 函数赋值 | Function<Integer, Integer> func = x -> x * x; | func = lambda x: x * x |
| 函数作为参数 | stream.map(func) | map(func, iterable) |
| 函数作为返回值 | 复杂 | 简单,直接返回函数 |
| 函数存储 | 复杂 | 简单,存储在列表、字典等 |
Python 函数作为对象示例:
# 函数赋值给变量
def add(a, b):
return a + b
addition = add
print(addition(3, 5)) # 8
# 函数作为参数
def apply_function(func, x, y):
return func(x, y)
result = apply_function(add, 10, 20)
print(result) # 30
# 函数作为返回值
def create_multiplier(factor):
def multiplier(x):
return x * factor
return multiplier
double = create_multiplier(2)
triple = create_multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
# 函数存储在列表中
functions = [add, lambda x, y: x - y, lambda x, y: x * y]
for func in functions:
print(func(10, 5)) # 15, 5, 50
# 函数存储在字典中
operations = {
"add": add,
"subtract": lambda x, y: x - y,
"multiply": lambda x, y: x * y,
"divide": lambda x, y: x / y
}
print(operations["add"](10, 5)) # 15
print(operations["subtract"](10, 5)) # 5
5.6 装饰器
Java 装饰器
- 使用设计模式中的装饰器模式
- 实现接口,包装原始对象
Python 装饰器
- 使用
@语法 - 函数装饰器
- 类装饰器
Python 装饰器示例:
# 简单装饰器
def log_function(func):
"""日志装饰器"""
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned {result}")
return result
return wrapper
@log_function
def add(a, b):
return a + b
print(add(3, 5)) # 会打印日志
# 带参数的装饰器
def repeat(n):
"""重复执行函数n次的装饰器"""
def decorator(func):
def wrapper(*args, **kwargs):
results = []
for i in range(n):
results.append(func(*args, **kwargs))
return results
return wrapper
return decorator
@repeat(3)
def greet(name):
return f"Hello, {name}!"
print(greet("Alice")) # 执行3次
# 类装饰器
class CountCalls:
"""统计函数调用次数的装饰器"""
def __init__(self, func):
self.func = func
self.calls = 0
def __call__(self, *args, **kwargs):
self.calls += 1
print(f"Call {self.calls} of {self.func.__name__}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello(name):
return f"Hello, {name}!"
print(say_hello("Bob"))
print(say_hello("Charlie"))
5.7 作用域
Java 作用域
- 类作用域
- 方法作用域
- 块作用域
- 局部变量
Python 作用域
- 全局作用域
- 局部作用域
- 嵌套作用域
- 内置作用域
对比:
| 作用域 | Java | Python |
|---|---|---|
| 全局变量 | 类变量 | 模块级变量 |
| 局部变量 | 方法内变量 | 函数内变量 |
| 嵌套作用域 | 无 | 支持(闭包) |
| 作用域访问 | 严格 | 更灵活(nonlocal, global) |
Python 作用域示例:
# 全局变量
global_var = "global"
def outer():
# 闭包变量
outer_var = "outer"
def inner():
# 局部变量
inner_var = "inner"
# 访问全局变量
print(global_var)
# 访问闭包变量
print(outer_var)
# 访问局部变量
print(inner_var)
inner()
outer()
# 修改全局变量
def modify_global():
global global_var
global_var = "modified global"
modify_global()
print(global_var) # modified global
# 修改闭包变量
def outer():
count = 0
def inner():
nonlocal count
count += 1
return count
return inner
counter = outer()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3
5.8 递归函数
Java 递归
public int factorial(int n) {
if (n == 0) {
return 1;
}
return n * factorial(n - 1);
}
Python 递归
def factorial(n):
if n == 0:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120
对比:
| 特性 | Java | Python |
|---|---|---|
| 递归深度 | 较深 | 较浅(默认递归深度限制) |
| 尾递归优化 | 部分 JVM 支持 | 不支持 |
| 语法 | 相同 | 相同 |
Python 递归示例:
# 斐波那契数列
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # 55
# 递归深度限制
import sys
print(sys.getrecursionlimit()) # 默认 1000
# 阶乘(递归)
def factorial(n):
if n == 0:
return 1
return n * factorial(n - 1)
print(factorial(100)) # 可以计算大的阶乘
5.9 内置函数
Java 内置方法
System.out.println()Math.abs()Arrays.sort()- 等等
Python 内置函数
print()len()range()sum()max()min()sorted()type()isinstance()- 等等
常用内置函数对比:
| 功能 | Java | Python |
|---|---|---|
| 打印 | System.out.println() | print() |
| 长度 | array.length 或 collection.size() | len() |
| 最大值 | Math.max() | max() |
| 最小值 | Math.min() | min() |
| 排序 | Arrays.sort() 或 Collections.sort() | sorted() |
| 类型检查 | instanceof 或 getClass() | type() 或 isinstance() |
| 输入 | Scanner 类 | input() |
5.10 练习
- 函数定义练习:定义一个函数,计算两个数的最大值
- 参数练习:定义一个函数,接受任意数量的参数,返回它们的平均值
- Lambda 练习:使用 lambda 函数和 filter(),过滤出列表中的所有奇数
- 装饰器练习:创建一个装饰器,计算函数执行时间
- 递归练习:定义一个递归函数,计算阶乘
- 函数作为对象练习:创建一个函数字典,实现简单的计算器
5.11 小结
- Python 的函数定义比 Java 更简洁,不需要声明参数和返回类型
- Python 支持默认参数、可变参数和关键字参数
- Python 支持函数作为一等公民,可以赋值、传递和返回
- Python 的 lambda 表达式比 Java 更简洁,常用于函数参数
- Python 支持装饰器,可以修改函数行为
- Python 的作用域规则更灵活,支持闭包
- Python 的内置函数比 Java 更丰富,使用更方便
- Python 的递归深度有限制,对于深层递归可能需要迭代实现
通过本章的学习,你已经了解了 Java 和 Python 在函数与方法上的主要区别。接下来,我们将学习 Python 的面向对象编程。