来源:04_函数 hm_01~hm_06 + Python官方文档 + 网络资料整理
一、详细讲解
1.1 核心概念
函数定义与调用是Python编程中的核心知识点,也是代码模块化、复用和组织的基石。在本课程的第10天,我们将系统学习函数的基本概念、定义语法、参数传递、返回值处理,以及文档字符串的编写。
函数是一段组织好的、可重复使用的、用来实现单一或相关联功能的代码块。在Python中,函数不仅是一种代码复用的手段,更是实现面向过程编程和模块化设计的基础。通过函数,我们可以将复杂的问题分解为多个小问题,使程序结构更加清晰、易于维护。
1.2 函数基础
1.2.1 为什么要使用函数
# 不使用函数:代码重复
print("=== 计算圆的面积 ===")
radius = 5
area = 3.14159 * radius ** 2
print(f"半径{radius}的圆面积: {area}")
radius = 10
area = 3.14159 * radius ** 2
print(f"半径{radius}的圆面积: {area}")
radius = 15
area = 3.14159 * radius ** 2
print(f"半径{radius}的圆面积: {area}")
# 使用函数:代码复用
def calculate_circle_area(radius):
"""计算圆的面积"""
area = 3.14159 * radius ** 2
return area
print("\n=== 使用函数 ===")
for r in [5, 10, 15]:
print(f"半径{r}的圆面积: {calculate_circle_area(r)}")
1.2.2 函数定义的基本语法
# 函数定义的基本结构
def 函数名(参数1, 参数2, ...):
"""文档字符串(可选)"""
# 函数体
return 返回值 # 可选
1.3 函数的定义与调用
1.3.1 无参函数
# 无参函数:不需要输入参数
def greet():
"""简单的问候函数"""
print("Hello, World!")
print("Welcome to Python!")
# 调用函数
greet()
# 可以多次调用
greet()
greet()
1.3.2 有参函数
# 有参函数:需要输入参数
def greet_person(name):
"""向指定的人打招呼"""
print(f"Hello, {name}!")
print(f"Welcome, {name}!")
# 调用函数,传入参数
greet_person("Alice")
print()
greet_person("Bob")
1.3.3 多参数函数
# 多个参数的函数
def calculate_rectangle(length, width):
"""计算矩形的面积和周长"""
area = length * width
perimeter = 2 * (length + width)
return area, perimeter
# 调用函数
result = calculate_rectangle(5, 3)
print(f"面积: {result[0]}, 周长: {result[1]}")
# 使用解包
area, perimeter = calculate_rectangle(5, 3)
print(f"面积: {area}")
print(f"周长: {perimeter}")
1.4 参数详解
1.4.1 位置参数
# 位置参数:按顺序传递
def introduce(name, age, city):
"""自我介绍"""
print(f"我叫{name},今年{age}岁,来自{city}。")
# 调用时按位置传递
introduce("张三", 25, "北京")
introduce("李四", 30, "上海")
introduce("王五", 28, "广州")
# 位置参数必须传递,且顺序不能错
# introduce("赵六") # 错误:缺少参数
# introduce(25, "钱七", "深圳") # 错误:类型不匹配
1.4.2 关键字参数
# 关键字参数:按名称传递
def introduce(name, age, city):
"""自我介绍"""
print(f"我叫{name},今年{age}岁,来自{city}。")
# 使用关键字参数,顺序可以改变
introduce(age=30, name="张三", city="北京")
# 混合使用:位置参数必须在关键字参数前面
introduce("李四", city="上海", age=28)
1.4.3 默认参数
# 默认参数:给参数设置默认值
def greet(name, greeting="Hello"):
"""带默认参数的问候函数"""
print(f"{greeting}, {name}!")
# 调用时可以不指定默认参数
greet("Alice") # Hello, Alice!
greet("Bob", "Hi") # Hi, Bob!
# 默认参数必须在位置参数后面
# def greet(greeting="Hello", name): # 错误!
# 默认参数可以是有副作用的可变对象(需要注意)
1.4.4 默认参数的最佳实践
# 避免使用可变对象作为默认参数
# 错误示例
def add_to_list(item, target_list=[]): # 危险!
target_list.append(item)
return target_list
print(add_to_list(1)) # [1]
print(add_to_list(2)) # [1, 2] - 不是 [2]!
# 正确示例
def add_to_list(item, target_list=None): # 正确
if target_list is None:
target_list = []
target_list.append(item)
return target_list
print(add_to_list(1)) # [1]
print(add_to_list(2)) # [2]
1.5 返回值详解
1.5.1 无返回值函数
# 没有return语句的函数,默认返回None
def print_sum(a, b):
"""打印两个数的和,不返回值"""
print(f"{a} + {b} = {a + b}")
result = print_sum(3, 5)
print(f"返回值: {result}") # None
# 使用return单独返回None
def check_positive(n):
"""检查是否是正数"""
if n > 0:
return True
else:
return None
print(check_positive(5)) # True
print(check_positive(-1)) # None
1.5.2 单返回值
# 返回单个值
def square(n):
"""返回n的平方"""
return n ** 2
result = square(5)
print(f"5的平方: {result}") # 25
1.5.3 多返回值
# 返回多个值(实际是返回元组)
def calculate(a, b):
"""返回和、差、积"""
return a + b, a - b, a * b
# 使用元组接收
result = calculate(10, 3)
print(f"结果类型: {type(result)}")
print(f"结果值: {result}")
# 使用解包接收
sum_val, diff, prod = calculate(10, 3)
print(f"和: {sum_val}, 差: {diff}, 积: {prod}")
1.5.4 提前返回
# 使用多个return语句
def absolute_value(n):
"""返回绝对值"""
if n < 0:
return -n
return n
print(absolute_value(-5)) # 5
print(absolute_value(5)) # 5
# 早期返回(Early Return)模式
def process_data(data):
"""处理数据"""
# 验证输入
if not data:
return None
# 主处理逻辑
result = []
for item in data:
if is_valid(item):
result.append(process(item))
return result
1.6 文档字符串(Docstring)
1.6.1 文档字符串的作用
文档字符串是紧跟在函数定义之后的一个字符串,用于说明函数的功能、参数、返回值、使用示例等信息。
def calculate_circle_area(radius):
"""
计算圆的面积
Parameters:
radius (float): 圆的半径,必须为非负数
Returns:
float: 圆的面积
Examples:
>>> calculate_circle_area(5)
78.53975
"""
if radius < 0:
raise ValueError("半径不能为负数")
return 3.14159 * radius ** 2
1.6.2 文档字符串的格式
# 单行文档字符串
def greet(name):
"""向指定的人打招呼。"""
print(f"Hello, {name}!")
# 多行文档字符串
def calculate_stats(numbers):
"""
计算一组数字的统计信息。
参数:
numbers (list): 数字列表
返回:
dict: 包含平均值、总和、最大值、最小值的字典
示例:
>>> calculate_stats([1, 2, 3, 4, 5])
{'avg': 3.0, 'sum': 15, 'max': 5, 'min': 1}
"""
return {
'avg': sum(numbers) / len(numbers),
'sum': sum(numbers),
'max': max(numbers),
'min': min(numbers)
}
# 访问文档字符串
print(calculate_stats.__doc__)
help(calculate_stats)
1.7 函数调用详解
1.7.1 函数调用的过程
# 函数调用过程分析
def add(a, b):
"""加法函数"""
result = a + b
return result
# 调用步骤:
# 1. 传递参数:a=3, b=5
# 2. 执行函数体:result = 8
# 3. 返回结果:return 8
# 4. 接收返回值:total = 8
total = add(3, 5)
print(f"结果: {total}")
1.7.2 嵌套调用
# 函数可以嵌套调用
def square(n):
"""返回n的平方"""
return n ** 2
def sum_of_squares(a, b):
"""返回a的平方加b的平方"""
return square(a) + square(b)
result = sum_of_squares(3, 4) # 3² + 4² = 9 + 16 = 25
print(f"3² + 4² = {result}")
1.8 变量的作用域
1.8.1 局部变量与全局变量
# 全局变量
global_var = "我是全局变量"
def test_scope():
# 局部变量
local_var = "我是局部变量"
print(f"函数内可以访问全局变量: {global_var}")
print(f"函数内可以访问局部变量: {local_var}")
test_scope()
# print(local_var) # 错误!局部变量在函数外无法访问
# 在函数内修改全局变量需要使用global关键字
counter = 0
def increment():
global counter
counter += 1
print(f"计数器: {counter}")
increment()
increment()
print(f"函数外计数器: {counter}")
1.8.2 LEGB规则
Python查找变量时遵循LEGB规则:
- Local:局部作用域
- Enclosing:闭包作用域
- Global:全局作用域
- Built-in:内置作用域
# LEGB规则示例
x = "全局变量"
def outer():
x = "闭包变量"
def inner():
x = "局部变量"
print(f"inner中的x: {x}") # 局部变量
inner()
print(f"outer中的x: {x}") # 闭包变量
outer()
print(f"全局中的x: {x}") # 全局变量
1.9 实用函数示例
1.9.1 数学运算函数
# 判断质数
def is_prime(n):
"""判断n是否为质数"""
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
# 打印n以内的所有质数
def print_primes(n):
"""打印n以内的所有质数"""
primes = []
for i in range(2, n + 1):
if is_prime(i):
primes.append(i)
return primes
print(f"100以内的质数: {print_primes(100)}")
# 计算阶乘
def factorial(n):
"""计算n的阶乘"""
if n < 0:
raise ValueError("负数没有阶乘")
if n <= 1:
return 1
result = 1
for i in range(2, n + 1):
result *= i
return result
print(f"5! = {factorial(5)}") # 120
1.9.2 字符串处理函数
# 反转字符串
def reverse_string(s):
"""反转字符串"""
return s[::-1]
print(f"反转'abcde': {reverse_string('abcde')}")
# 判断回文
def is_palindrome(s):
"""判断是否为回文"""
clean = ''.join(c.lower() for c in s if c.isalnum())
return clean == clean[::-1]
print(f"'上海自来水来自海上'是回文: {is_palindrome('上海自来水来自海上')}")
# 统计单词数
def count_words(text):
"""统计单词数量"""
words = text.split()
return len(words)
print(f"'Hello World Python'有 {count_words('Hello World Python')} 个单词")
1.9.3 数据验证函数
# 验证邮箱格式
def is_valid_email(email):
"""简单验证邮箱格式"""
import re
pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
return bool(re.match(pattern, email))
emails = ["test@example.com", "invalid-email", "user@domain.org"]
for email in emails:
print(f"{email}: {is_valid_email(email)}")
# 验证数字范围
def is_in_range(value, min_val, max_val):
"""验证值是否在指定范围内"""
return min_val <= value <= max_val
print(f"5在1-10范围内: {is_in_range(5, 1, 10)}")
1.10 最佳实践
1.10.1 函数设计原则
# 单一职责原则:每个函数只做一件事
# 不好:一个函数做多件事
def process_user(name, age, action):
if action == "create":
print(f"创建用户 {name}, 年龄 {age}")
elif action == "delete":
print(f"删除用户 {name}")
elif action == "update":
print(f"更新用户 {name}, 年龄 {age}")
# 好:每个函数职责单一
def create_user(name, age):
"""创建用户"""
print(f"创建用户 {name}, 年龄 {age}")
def delete_user(name):
"""删除用户"""
print(f"删除用户 {name}")
def update_user(name, age):
"""更新用户"""
print(f"更新用户 {name}, 年龄 {age}")
1.10.2 参数设计建议
# 使用有意义的参数名
def calculate_area(width, height): # 好
return width * height
# 避免使用魔法数字
def calculate_circle_area(radius, pi=3.14159): # 使用默认参数
return pi * radius ** 2
1.10.3 文档字符串编写规范
# 使用docstring格式
def function_name(param1, param2):
"""
简短描述(第一行以动词开头,句号结尾)
详细描述(可选,说明函数的工作原理)
Args:
param1: 参数1的说明
param2: 参数2的说明
Returns:
返回值的说明
Raises:
ValueError: 何时抛出此异常
Examples:
>>> function_name(1, 2)
3
"""
pass
1.11 常见错误与调试
1.11.1 常见错误
# 错误1:忘记写冒号
# def greet(name) # 缺少冒号
# print(f"Hello, {name}")
# 错误2:参数名拼写错误
def greet(name):
print(f"Hello, {name}")
# greet(neme) # NameError: name 'neme' is not defined
# 错误3:参数数量不匹配
def add(a, b):
return a + b
# add(1) # TypeError: add() missing 1 required argument
# add(1, 2, 3) # TypeError: add() takes 2 positional arguments but 3 were given
# 错误4:修改不可变对象
# def modify_immutable(s):
# s += " world" # 创建了新字符串,原字符串不变
1.11.2 调试技巧
# 使用print调试
def buggy_function(n):
print(f"[DEBUG] 输入: {n}")
result = 0
for i in range(n):
result += i
print(f"[DEBUG] i={i}, result={result}")
return result
# 使用assert调试
def divide(a, b):
assert b != 0, "除数不能为零"
return a / b
二、背诵版
Day10 要点速记: 【函数定义】 def 函数名(参数1, 参数2, ...): """文档字符串""" 函数体 return 返回值 【参数类型】 - 位置参数:按顺序传递 - 关键字参数:按名称传递 - 默认参数:parameter=默认值 - *args:**kwargs 【返回值】 - 无return:返回None - return 值:返回单个值 - return 值1, 值2:返回元组 【文档字符串】 单行:"""简洁描述""" 多行:详细说明Args/Returns/Examples 【作用域】 LEGB: Local → Enclosing → Global → Built-in global关键字:在函数内修改全局变量三、考前记忆
| 要素 | 内容 |
|---|---|
| 今日主题 | 函数定义与调用 |
| 关键词 | 函数定义、调用、参数、返回值、文档字符串 |
| 定义语法 | def 函数名(参数): |
| 返回值 | 无return返回None |
| 多返回值 | return a, b(返回元组) |
| 文档字符串 | 函数后的三引号字符串 |
| 参数传递 | 位置参数、关键字参数、默认参数 |
| 重要考点 | 参数传递、返回值处理、作用域 |
四、测试题
1. 单选题: 以下哪个是函数定义的正确语法?
- A. function greet(name):
- B. def greet(name):
- C. func greet(name):
- D. greet(name) def:
2. 单选题: 函数没有return语句时,返回值是什么?
- A. 0
- B. ""
- C. None
- D. False
3. 单选题: 以下代码的输出是什么?
def test(a, b=10):
return a + b
print(test(5))
- A. 5
- B. 10
- C. 15
- D. 错误
4. 填空题: return语句可以返回 _______(填"一个"或"多个")值。
5. 填空题: 在函数内部修改全局变量,需要使用 _______ 关键字。
6. 简答题: 请说明位置参数和关键字参数的区别。
7. 代码题: 定义一个函数,接受两个参数x和y,返回它们的和、差、积。
8. 代码题: 定义一个函数,计算一个列表中所有正整数的和。
9. 代码题: 为以下函数编写文档字符串:
def find_max(numbers):
# 找出列表中的最大值
if not numbers:
return None
max_val = numbers[0]
for num in numbers:
if num > max_val:
max_val = num
return max_val
10. 综合题: 设计一个计算器程序,包含加、减、乘、除四个函数,用户输入两个数和一个运算符,程序返回计算结果。
-
B - Python函数定义使用def关键字
-
C - 函数没有return语句时,默认返回None
-
C - b使用默认值10,所以5+10=15
-
多个 - return可以返回多个值,实际是返回元组
-
global - 使用global关键字可以在函数内修改全局变量
def calculate(a, b):
"""返回a和b的和、差、积"""
return a + b, a - b, a * b
sum_val, diff, prod = calculate(10, 3)
print(f"和: {sum_val}, 差: {diff}, 积: {prod}")
def sum_positive(numbers):
"""计算列表中所有正整数的和"""
total = 0
for num in numbers:
if num > 0:
total += num
return total
print(sum_positive([1, -2, 3, -4, 5])) # 9
def find_max(numbers):
"""
找出列表中的最大值。
Parameters:
numbers (list): 数字列表
Returns:
number or None: 列表中的最大值,如果列表为空则返回None
Examples:
>>> find_max([1, 5, 3, 9, 2])
9
>>> find_max([])
None
"""
if not numbers:
return None
max_val = numbers[0]
for num in numbers:
if num > max_val:
max_val = num
return max_val
def add(a, b):
"""加法"""
return a + b
def subtract(a, b):
"""减法"""
return a - b
def multiply(a, b):
"""乘法"""
return a * b
def divide(a, b):
"""除法"""
if b == 0:
return "错误:除数不能为零"
return a / b
operations = {
'+': add,
'-': subtract,
'*': multiply,
'/': divide
}
def calculator():
"""简单计算器"""
print("=== 简单计算器 ===")
try:
num1 = float(input("请输入第一个数: "))
operator = input("请输入运算符(+,-,*,/): ")
num2 = float(input("请输入第二个数: "))
if operator not in operations:
print("无效的运算符")
return
result = operations[operator](num1, num2)
print(f"结果: {num1} {operator} {num2} = {result}")
except ValueError:
print("输入无效")
calculator()
五、扩展阅读
5.1 函数注解(Type Hints)
Python 3.5+支持函数注解,用于指定参数和返回值的类型:
def greet(name: str, times: int = 1) -> str:
"""打招呼"""
return (f"Hello, {name}! " * times).strip()
# 使用函数注解
print(greet("Alice", 2))
# 运行时获取注解
print(greet.__annotations__)
5.2 高阶函数
函数可以像变量一样作为参数传递:
def apply_twice(func, value):
"""对值应用函数两次"""
return func(func(value))
def square(x):
return x ** 2
print(apply_twice(square, 3)) # (3²)² = 81
5.3 匿名函数(Lambda)
# 使用lambda表达式创建简短函数
square = lambda x: x ** 2
print(square(5)) # 25
# 与内置函数结合使用
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x ** 2, numbers))
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(f"平方: {squares}")
print(f"偶数: {evens}")
恭喜完成Day10学习!Python基础循环与函数部分已全部完成。明天的Day11将进一步学习函数的返回值高级应用。