文章目录
- 前言
- 一、函数基础
-
- [1. 函数的定义与调用](#1. 函数的定义与调用)
- [2. 返回值:return语句](#2. 返回值:return语句)
- 二、函数参数详解
-
- [1. 位置参数(Positional Arguments)](#1. 位置参数(Positional Arguments))
- [2. 关键字参数(Keyword Arguments)](#2. 关键字参数(Keyword Arguments))
- [3. 默认参数(Default Arguments)](#3. 默认参数(Default Arguments))
- [4. 可变参数(*args和**kwargs)](#4. 可变参数(*args和**kwargs))
- [5. 参数解包(*和**运算符)](#5. 参数解包(*和**运算符))
- 三、函数作用域
-
- [1. 局部变量 vs 全局变量](#1. 局部变量 vs 全局变量)
- [2. nonlocal关键字](#2. nonlocal关键字)
- 四、高级函数特性
-
- [1. 函数作为参数(高阶函数)](#1. 函数作为参数(高阶函数))
- [2. 闭包(Closure)](#2. 闭包(Closure))
- [3. 装饰器(Decorator)基础](#3. 装饰器(Decorator)基础)
- [4. 生成器函数(Generator Functions)](#4. 生成器函数(Generator Functions))
- 五、文档字符串和类型提示
-
- [1. 文档字符串(Docstrings)](#1. 文档字符串(Docstrings))
- [2. 类型提示(Type Hints)](#2. 类型提示(Type Hints))
前言
本文主要介绍了函数基础、函数参数详解、函数作用域和高级函数特性等知识点。
一、函数基础
1. 函数的定义与调用
python
python
# 定义一个简单的函数
def greet():
"""这是一个简单的问候函数"""
print("Hello, World!")
# 调用函数
greet() # 输出: Hello, World!
greet() # 可以多次调用
greet()
# 带参数的函数
def greet_person(name):
"""向指定的人打招呼"""
print(f"Hello, {name}!")
# 调用带参数的函数
greet_person("Alice") # 输出: Hello, Alice!
greet_person("Bob") # 输出: Hello, Bob!
# 带多个参数的函数
def introduce(name, age, city):
"""介绍一个人"""
print(f"我叫{name},今年{age}岁,来自{city}。")
introduce("张三", 25, "北京") # 输出: 我叫张三,今年25岁,来自北京。
2. 返回值:return语句
python
python
# 没有return语句的函数返回None
def add_without_return(a, b):
"""这个函数没有return语句"""
result = a + b
# 注意:没有return!
print(add_without_return(3, 5)) # 输出: None
# 有return语句的函数
def add(a, b):
"""返回两个数的和"""
result = a + b
return result
sum_result = add(3, 5)
print(f"3 + 5 = {sum_result}") # 输出: 3 + 5 = 8
# 可以立即使用返回值
print(f"10 + 20 = {add(10, 20)}") # 输出: 10 + 20 = 30
# 多个return语句
def get_grade(score):
"""根据分数返回等级"""
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"
print(f"85分 -> {get_grade(85)}") # 输出: B
print(f"95分 -> {get_grade(95)}") # 输出: A
print(f"55分 -> {get_grade(55)}") # 输出: F
# 返回多个值(实际上是返回一个元组)
def calculate_stats(numbers):
"""计算统计信息"""
count = len(numbers)
total = sum(numbers)
average = total / count if count > 0 else 0
maximum = max(numbers) if numbers else 0
minimum = min(numbers) if numbers else 0
return count, total, average, maximum, minimum
# 接收多个返回值
scores = [85, 92, 78, 90, 88]
count, total, avg, max_val, min_val = calculate_stats(scores)
print(f"统计结果:")
print(f" 数量: {count}")
print(f" 总分: {total}")
print(f" 平均分: {avg:.2f}")
print(f" 最高分: {max_val}")
print(f" 最低分: {min_val}")
# 也可以作为元组接收
stats = calculate_stats(scores)
print(f"\n元组形式: {stats}")
print(f"平均分: {stats[2]:.2f}")
二、函数参数详解
1. 位置参数(Positional Arguments)
python
python
def describe_pet(animal_type, pet_name):
"""描述宠物"""
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
# 位置参数必须按顺序传递
describe_pet("dog", "Buddy")
# 输出:
# I have a dog.
# My dog's name is Buddy.
describe_pet("Buddy", "dog") # 参数顺序错误!
# 输出:
# I have a Buddy. # 错误!
# My Buddy's name is dog.
2. 关键字参数(Keyword Arguments)
python
python
def describe_pet(animal_type, pet_name):
"""描述宠物"""
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
# 使用关键字参数,顺序不重要
describe_pet(pet_name="Buddy", animal_type="dog")
describe_pet(animal_type="cat", pet_name="Whiskers")
# 混合使用位置参数和关键字参数
# 规则:位置参数必须在关键字参数之前
describe_pet("hamster", pet_name="Nibbles") # 正确
# describe_pet(pet_name="Nibbles", "hamster") # 错误!位置参数必须在关键字参数之前
3. 默认参数(Default Arguments)
python
python
def describe_pet(pet_name, animal_type="dog"):
"""描述宠物,animal_type有默认值"""
print(f"I have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name}.")
# 使用默认参数
describe_pet("Buddy") # animal_type使用默认值"dog"
# 输出:
# I have a dog.
# My dog's name is Buddy.
describe_pet("Whiskers", "cat") # 提供animal_type参数
describe_pet("Nibbles", animal_type="hamster") # 使用关键字参数
# 重要:默认参数的值在函数定义时计算
def add_item(item, items=[]): # 危险!默认值是可变对象
"""添加项目到列表(有问题的实现)"""
items.append(item)
return items
# 测试
print(add_item("apple")) # ['apple']
print(add_item("banana")) # ['apple', 'banana'] 注意:保留了上次的结果!
print(add_item("orange")) # ['apple', 'banana', 'orange']
# 正确的做法:使用None作为默认值
def add_item_safe(item, items=None):
"""添加项目到列表(安全的实现)"""
if items is None:
items = [] # 每次调用都创建新列表
items.append(item)
return items
print(add_item_safe("apple")) # ['apple']
print(add_item_safe("banana")) # ['banana'] 正确:每次都是新列表
print(add_item_safe("orange")) # ['orange']
4. 可变参数(*args和**kwargs)
python
python
# *args:接收任意数量的位置参数
def sum_all(*args):
"""计算所有参数的和"""
print(f"参数: {args} (类型: {type(args)})")
return sum(args)
print(f"sum_all(1, 2, 3) = {sum_all(1, 2, 3)}")
# 输出:
# 参数: (1, 2, 3) (类型: <class 'tuple'>)
# sum_all(1, 2, 3) = 6
print(f"sum_all(10, 20, 30, 40, 50) = {sum_all(10, 20, 30, 40, 50)}")
# 输出: 150
# **kwargs:接收任意数量的关键字参数
def print_info(**kwargs):
"""打印所有关键字参数"""
print(f"关键字参数: {kwargs} (类型: {type(kwargs)})")
for key, value in kwargs.items():
print(f" {key}: {value}")
print_info(name="Alice", age=25, city="New York")
# 输出:
# 关键字参数: {'name': 'Alice', 'age': 25, 'city': 'New York'} (类型: <class 'dict'>)
# name: Alice
# age: 25
# city: New York
# 混合使用所有参数类型
def complex_function(positional, default="default", *args, **kwargs):
"""演示所有参数类型的函数"""
print(f"位置参数: {positional}")
print(f"默认参数: {default}")
print(f"可变位置参数 (*args): {args}")
print(f"可变关键字参数 (**kwargs): {kwargs}")
print("-" * 40)
# 调用示例
complex_function("第一位置参数")
complex_function("第一位置参数", "自定义默认值")
complex_function("第一位置参数", "自定义默认值", "额外1", "额外2")
complex_function("第一位置参数", "自定义默认值", "额外1", "额外2", key1="值1", key2="值2")
# 实际应用:配置函数
def configure_database(host, port=5432, *args, **kwargs):
"""配置数据库连接"""
print(f"数据库配置:")
print(f" 主机: {host}")
print(f" 端口: {port}")
if args:
print(f" 额外位置参数: {args}")
if kwargs:
print(" 额外选项:")
for key, value in kwargs.items():
print(f" {key}: {value}")
return {"host": host, "port": port, **kwargs}
# 使用
config = configure_database("localhost", 3306, "extra_arg", username="admin", password="secret", database="test")
5. 参数解包(*和**运算符)
python
python
# 使用*解包列表/元组
def print_coordinates(x, y, z):
"""打印三维坐标"""
print(f"坐标: ({x}, {y}, {z})")
point = [10, 20, 30]
print_coordinates(*point) # 等价于 print_coordinates(10, 20, 30)
# 使用**解包字典
def print_person_info(name, age, city):
"""打印个人信息"""
print(f"姓名: {name}")
print(f"年龄: {age}")
print(f"城市: {city}")
person = {"name": "张三", "age": 25, "city": "北京"}
print_person_info(**person) # 等价于 print_person_info(name="张三", age=25, city="北京")
# 结合使用
def complex_function(a, b, c, d, e):
"""复杂函数示例"""
print(f"a={a}, b={b}, c={c}, d={d}, e={e}")
args_list = [1, 2]
kwargs_dict = {"d": 4, "e": 5}
complex_function(*args_list, 3, **kwargs_dict) # a=1, b=2, c=3, d=4, e=5
三、函数作用域
1. 局部变量 vs 全局变量
python
python
# 全局变量
global_var = "我是全局变量"
def function1():
"""函数1:使用全局变量"""
print(f"在function1中: {global_var}")
def function2():
"""函数2:创建同名局部变量"""
global_var = "我是局部变量" # 创建新的局部变量,不影响全局变量
print(f"在function2中: {global_var}")
def function3():
"""函数3:修改全局变量"""
global global_var # 声明使用全局变量
global_var = "我修改了全局变量"
print(f"在function3中: {global_var}")
# 测试
print(f"初始全局变量: {global_var}") # 我是全局变量
function1() # 在function1中: 我是全局变量
function2() # 在function2中: 我是局部变量
print(f"调用function2后: {global_var}") # 我还是全局变量(未改变)
function3() # 在function3中: 我修改了全局变量
print(f"调用function3后: {global_var}") # 我修改了全局变量
# 嵌套作用域
def outer_function():
"""外层函数"""
outer_var = "外层变量"
def inner_function():
"""内层函数"""
inner_var = "内层变量"
print(f"内层函数可以访问: {outer_var}") # 可以访问外层变量
print(f"内层函数有自己的: {inner_var}")
inner_function()
# print(f"外层函数不能访问: {inner_var}") # 错误!不能访问内层变量
outer_function()
2. nonlocal关键字
python
python
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
# 对比:不使用nonlocal
def outer_no_nonlocal():
"""外层函数"""
count = 0
def inner():
"""内层函数 - 不能修改外层变量"""
# 这里会创建新的局部变量count
count = 10 # 这是新的局部变量,不是修改外层变量
return count
print(f"调用inner前: count = {count}")
result = inner()
print(f"调用inner后: count = {count}, inner返回: {result}")
return count
result = outer_no_nonlocal()
# 输出:
# 调用inner前: count = 0
# 调用inner后: count = 0, inner返回: 10
四、高级函数特性
1. 函数作为参数(高阶函数)
python
python
def apply_operation(numbers, operation):
"""对列表中的每个元素应用操作"""
return [operation(x) for x in numbers]
def square(x):
"""平方"""
return x ** 2
def double(x):
"""加倍"""
return x * 2
def add_five(x):
"""加5"""
return x + 5
# 测试
numbers = [1, 2, 3, 4, 5]
print(f"原列表: {numbers}")
print(f"平方: {apply_operation(numbers, square)}")
print(f"加倍: {apply_operation(numbers, double)}")
print(f"加5: {apply_operation(numbers, add_five)}")
# 使用lambda函数(匿名函数)
print(f"立方: {apply_operation(numbers, lambda x: x ** 3)}")
print(f"平方根: {apply_operation(numbers, lambda x: x ** 0.5)}")
# 内置高阶函数示例
from functools import reduce
numbers = [1, 2, 3, 4, 5]
# map: 应用函数到每个元素
squares = list(map(lambda x: x**2, numbers))
print(f"map平方: {squares}")
# filter: 过滤元素
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(f"filter偶数: {evens}")
# reduce: 累积计算
product = reduce(lambda x, y: x * y, numbers)
print(f"reduce乘积: {product}")
2. 闭包(Closure)
python
python
def make_multiplier(factor):
"""创建乘法器闭包"""
def multiplier(x):
return x * factor
return multiplier
# 创建不同的乘法器
double = make_multiplier(2)
triple = make_multiplier(3)
quadruple = make_multiplier(4)
print(f"double(5) = {double(5)}") # 10
print(f"triple(5) = {triple(5)}") # 15
print(f"quadruple(5) = {quadruple(5)}") # 20
# 更复杂的闭包:计数器工厂
def create_counter(start=0, step=1):
"""创建计数器闭包"""
count = start
def counter():
nonlocal count
current = count
count += step
return current
return counter
# 创建不同的计数器
simple_counter = create_counter()
even_counter = create_counter(start=0, step=2)
odd_counter = create_counter(start=1, step=2)
print("\n简单计数器:")
for _ in range(5):
print(simple_counter(), end=" ") # 0 1 2 3 4
print("\n偶数计数器:")
for _ in range(5):
print(even_counter(), end=" ") # 0 2 4 6 8
print("\n奇数计数器:")
for _ in range(5):
print(odd_counter(), end=" ") # 1 3 5 7 9
3. 装饰器(Decorator)基础
python
python
# 简单的装饰器
def simple_decorator(func):
"""简单的装饰器:在函数调用前后打印信息"""
def wrapper():
print("函数调用前...")
result = func()
print("函数调用后...")
return result
return wrapper
@simple_decorator
def say_hello():
"""被装饰的函数"""
print("Hello!")
# 使用装饰器
say_hello()
# 输出:
# 函数调用前...
# Hello!
# 函数调用后...
# 带参数的装饰器
def repeat(n):
"""重复执行n次的装饰器"""
def decorator(func):
def wrapper(*args, **kwargs):
results = []
for i in range(n):
print(f"第{i+1}次执行:")
result = func(*args, **kwargs)
results.append(result)
return results
return wrapper
return decorator
@repeat(3)
def greet(name):
"""被装饰的函数"""
print(f"Hello, {name}!")
return f"Greeted {name}"
print("\n重复执行装饰器:")
results = greet("Alice")
print(f"所有结果: {results}")
# 实用的装饰器:计时器
import time
def timer(func):
"""计时装饰器"""
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"函数 {func.__name__} 执行时间: {end_time - start_time:.6f}秒")
return result
return wrapper
@timer
def slow_function():
"""模拟耗时操作"""
time.sleep(0.5)
return "完成"
@timer
def fast_function():
"""快速函数"""
return "快速完成"
print("\n计时装饰器:")
slow_function()
fast_function()
4. 生成器函数(Generator Functions)
python
python
# 普通函数 vs 生成器函数
def normal_range(n):
"""普通函数:返回列表"""
result = []
for i in range(n):
result.append(i)
return result
def generator_range(n):
"""生成器函数:使用yield"""
for i in range(n):
yield i
# 比较内存使用
print("普通函数(占用内存):")
normal_result = normal_range(1000000)
print(f"类型: {type(normal_result)}")
print(f"内存大小: {normal_result.__sizeof__():,} bytes")
print("\n生成器函数(节省内存):")
gen_result = generator_range(1000000)
print(f"类型: {type(gen_result)}")
print(f"内存大小: {gen_result.__sizeof__():,} bytes")
# 使用生成器
print("\n使用生成器:")
counter = generator_range(5)
print(next(counter)) # 0
print(next(counter)) # 1
print(next(counter)) # 2
# 使用for循环
print("使用for循环:")
for value in generator_range(3):
print(value)
# 实用的生成器:读取大文件
def read_large_file(file_path):
"""逐行读取大文件"""
with open(file_path, 'r', encoding='utf-8') as file:
for line in file:
yield line.strip()
# 模拟使用
def process_file():
"""处理文件内容"""
# 假设我们有一个大文件
# for line in read_large_file("large_file.txt"):
# process_line(line)
print("这里会逐行处理大文件,而不一次加载到内存")
process_file()
五、文档字符串和类型提示
1. 文档字符串(Docstrings)
python
python
def calculate_bmi(weight, height):
"""
计算身体质量指数(BMI)。
参数:
weight (float): 体重,单位千克
height (float): 身高,单位米
返回:
float: BMI值
str: BMI分类
示例:
>>> calculate_bmi(70, 1.75)
(22.86, '正常')
公式:
BMI = weight / (height ** 2)
"""
bmi = weight / (height ** 2)
if bmi < 18.5:
category = "偏瘦"
elif bmi < 24:
category = "正常"
elif bmi < 28:
category = "超重"
else:
category = "肥胖"
return round(bmi, 2), category
# 查看文档字符串
print("文档字符串:")
print(calculate_bmi.__doc__)
# 使用help函数
# help(calculate_bmi)
# 使用函数
bmi, category = calculate_bmi(70, 1.75)
print(f"\nBMI: {bmi}, 分类: {category}")
2. 类型提示(Type Hints)
python
python
from typing import List, Tuple, Dict, Optional, Union
def process_data(
numbers: List[int],
multiplier: float = 1.0,
include_negatives: bool = False
) -> Tuple[List[float], Dict[str, Union[int, float]]]:
"""
处理数字列表,返回处理结果和统计信息。
类型提示示例:
- List[int]: 整数列表
- float: 浮点数
- bool: 布尔值
- Tuple[...]: 元组
- Dict[str, Union[int, float]]: 字典,值为整数或浮点数
"""
if not include_negatives:
numbers = [n for n in numbers if n >= 0]
processed = [n * multiplier for n in numbers]
stats = {
"count": len(processed),
"sum": sum(processed),
"average": sum(processed) / len(processed) if processed else 0,
"max": max(processed) if processed else 0,
"min": min(processed) if processed else 0
}
return processed, stats
# 使用
data = [1, 2, 3, 4, 5, -1, -2]
processed, stats = process_data(data, multiplier=2.0, include_negatives=False)
print(f"处理后的数据: {processed}")
print(f"统计信息: {stats}")
# Optional类型:可能为None
def find_user(user_id: int) -> Optional[Dict]:
"""根据ID查找用户,可能返回None"""
users = {
1: {"name": "Alice", "age": 25},
2: {"name": "Bob", "age": 30}
}
return users.get(user_id)
# 使用
user = find_user(1)
if user:
print(f"找到用户: {user}")
else:
print("用户不存在")