Python函数:def一行搞定,不用声明返回类型,还能返回多个值
函数是代码复用的基本单位,是组织代码的核心工具。Python的函数比C语言更灵活,支持默认参数、关键字参数、可变参数等特性。本篇将详细介绍Python函数的定义、调用、参数传递及高级特性。
- Python函数基础
1. 函数的定义与调用
1.1 基本语法
# 函数定义
def 函数名(参数列表):
"""文档字符串(可选)"""
函数体
return 返回值 # 可选
# 示例
def greet(name):
"""向指定的人打招呼"""
return f"Hello, {name}!"
# 函数调用
message = greet("张三")
print(message) # Hello, 张三!
# 无参数函数
def say_hello():
print("Hello, World!")
say_hello()
# 无返回值函数
def print_info(name, age):
print(f"姓名:{name}")
print(f"年龄:{age}")
print_info("张三", 25)
1.2 函数文档字符串
def calculate_area(length, width):
"""
计算矩形面积。
Args:
length: 矩形的长度
width: 矩形的宽度
Returns:
矩形的面积
Raises:
ValueError: 如果长度或宽度为负数
Example:
>>> calculate_area(3, 4)
12
"""
if length < 0 or width < 0:
raise ValueError("长度和宽度不能为负数")
return length * width
# 查看文档
print(calculate_area.__doc__)
help(calculate_area)
1.3 与C语言函数对比
| 特性 | C语言 | Python |
|---|---|---|
| 返回类型 | 必须声明 | 不需要 |
| 参数类型 | 必须声明 | 不需要 |
| 默认参数 | C99支持 | 原生支持 |
| 可变参数 | ...和va_list | *args, **kwargs |
| 函数重载 | 不支持 | 不支持(但可用默认参数模拟) |
| 返回多值 | 需要指针或结构体 | 直接返回元组 |
// C语言函数
int add(int a, int b) {
return a + b;
}
# Python函数
def add(a, b):
return a + b
2. 函数参数
2.1 位置参数
def greet(name, greeting):
return f"{greeting}, {name}!"
# 按位置传参
print(greet("张三", "你好")) # 你好, 张三!
# 参数顺序很重要
print(greet("你好", "张三")) # 张三, 你好!(顺序错了)
2.2 默认参数
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
# 使用默认值
print(greet("张三")) # Hello, 张三!
# 覆盖默认值
print(greet("张三", "你好")) # 你好, 张三!
# 多个默认参数
def create_user(name, age=18, city="北京", active=True):
return {
"name": name,
"age": age,
"city": city,
"active": active
}
print(create_user("张三"))
print(create_user("李四", 25))
print(create_user("王五", city="上海"))
# ⚠️ 注意:默认参数必须在非默认参数之后
# def func(a=1, b): # SyntaxError
# pass
2.3 关键字参数
def greet(name, greeting):
return f"{greeting}, {name}!"
# 使用关键字参数(顺序无关)
print(greet(name="张三", greeting="你好"))
print(greet(greeting="你好", name="张三"))
# 混合使用(位置参数必须在前)
print(greet("张三", greeting="你好"))
# print(greet(name="张三", "你好")) # SyntaxError
2.4 可变位置参数(*args)
def sum_all(*args):
"""接收任意数量的位置参数"""
print(f"args类型:{type(args)}") # <class 'tuple'>
print(f"args内容:{args}")
return sum(args)
print(sum_all(1, 2, 3)) # 6
print(sum_all(1, 2, 3, 4, 5)) # 15
# 与普通参数混合
def greet_all(greeting, *names):
for name in names:
print(f"{greeting}, {name}!")
greet_all("Hello", "张三", "李四", "王五")
# 解包列表作为参数
numbers = [1, 2, 3, 4, 5]
print(sum_all(*numbers)) # 15
2.5 可变关键字参数(**kwargs)
def print_info(**kwargs):
"""接收任意数量的关键字参数"""
print(f"kwargs类型:{type(kwargs)}") # <class 'dict'>
print(f"kwargs内容:{kwargs}")
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="张三", age=25, city="北京")
# 与普通参数混合
def create_profile(name, **extra):
profile = {"name": name}
profile.update(extra)
return profile
print(create_profile("张三", age=25, city="北京"))
# 解包字典作为参数
info = {"age": 25, "city": "北京"}
print(create_profile("张三", **info))
2.6 参数组合
参数的顺序规则:位置参数 → 默认参数 → *args → 关键字参数 → **kwargs
def func(a, b, c=3, *args, d=4, **kwargs):
print(f"a={a}, b={b}, c={c}")
print(f"args={args}")
print(f"d={d}")
print(f"kwargs={kwargs}")
func(1, 2)
func(1, 2, 3, 4, 5, d=6, e=7, f=8)
# 实际应用示例
def log(message, *args, level="INFO", **kwargs):
"""灵活的日志函数"""
formatted = message.format(*args, **kwargs) if args or kwargs else message
print(f"[{level}] {formatted}")
log("简单消息")
log("用户{}登录", "张三")
log("用户{name}在{time}登录", name="张三", time="10:00")
log("错误发生", level="ERROR")
2.7 仅限位置参数和仅限关键字参数
# Python 3.8+:仅限位置参数(/之前)
def greet(name, /, greeting="Hello"):
return f"{greeting}, {name}!"
greet("张三") # OK
greet("张三", "你好") # OK
# greet(name="张三") # TypeError
# 仅限关键字参数(*之后)
def greet(name, *, greeting="Hello"):
return f"{greeting}, {name}!"
greet("张三") # OK
greet("张三", greeting="你好") # OK
# greet("张三", "你好") # TypeError
# 组合使用
def func(pos_only, /, standard, *, kw_only):
print(pos_only, standard, kw_only)
func(1, 2, kw_only=3) # OK
func(1, standard=2, kw_only=3) # OK
3. 返回值
3.1 单个返回值
def add(a, b):
return a + b
result = add(3, 5)
print(result) # 8
3.2 多个返回值
# 返回元组(最常用)
def get_min_max(numbers):
return min(numbers), max(numbers)
min_val, max_val = get_min_max([3, 1, 4, 1, 5, 9])
print(f"最小值:{min_val}, 最大值:{max_val}")
# 返回字典
def analyze_text(text):
return {
"length": len(text),
"words": len(text.split()),
"chars": len(text.replace(" ", ""))
}
result = analyze_text("Hello World")
print(result)
# 返回命名元组(更清晰)
from collections import namedtuple
Stats = namedtuple('Stats', ['min', 'max', 'avg'])
def get_stats(numbers):
return Stats(
min=min(numbers),
max=max(numbers),
avg=sum(numbers) / len(numbers)
)
stats = get_stats([1, 2, 3, 4, 5])
print(f"最小:{stats.min}, 最大:{stats.max}, 平均:{stats.avg}")
3.3 无返回值
def print_hello():
print("Hello")
# 没有return语句
result = print_hello()
print(result) # None
# 显式返回None
def do_nothing():
return None
# 提前返回
def check_positive(n):
if n <= 0:
return # 返回None
print(f"{n}是正数")
4. 变量作用域
4.1 局部变量与全局变量
# 全局变量
global_var = "我是全局变量"
def func():
# 局部变量
local_var = "我是局部变量"
print(global_var) # 可以读取全局变量
print(local_var)
func()
print(global_var)
# print(local_var) # NameError: 局部变量在函数外不可见
4.2 global关键字
counter = 0
def increment():
global counter # 声明使用全局变量
counter += 1
increment()
increment()
print(counter) # 2
# 不使用global会创建新的局部变量
x = 10
def func():
x = 20 # 这是新的局部变量,不是全局的x
print(f"函数内x:{x}")
func()
print(f"全局x:{x}") # 仍然是10
4.3 nonlocal关键字
def outer():
x = 10
def inner():
nonlocal x # 声明使用外层函数的变量
x += 1
print(f"inner中x:{x}")
inner()
print(f"outer中x:{x}")
outer()
# inner中x:11
# outer中x:11
4.4 LEGB规则
Python查找变量的顺序:Local → Enclosing → Global → Built-in
x = "global"
def outer():
x = "enclosing"
def inner():
x = "local"
print(x) # local
inner()
print(x) # enclosing
outer()
print(x) # global
# Built-in示例
print(len([1, 2, 3])) # len是内置函数
# 不要覆盖内置名称
# list = [1, 2, 3] # 不推荐!会覆盖内置的list
5. Lambda表达式
Lambda是匿名函数,用于创建简单的单行函数。
# 语法:lambda 参数: 表达式
# 基本用法
add = lambda a, b: a + b
print(add(3, 5)) # 8
# 等价于
def add(a, b):
return a + b
# 常见用途:作为参数传递
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
# 排序
sorted_nums = sorted(numbers) # 默认升序
sorted_nums = sorted(numbers, key=lambda x: -x) # 降序
# 按绝对值排序
numbers = [-3, 1, -4, 1, 5, -9]
sorted_nums = sorted(numbers, key=lambda x: abs(x))
print(sorted_nums) # [1, 1, -3, -4, 5, -9]
# 按字符串长度排序
words = ["apple", "pie", "banana", "cherry"]
sorted_words = sorted(words, key=lambda w: len(w))
print(sorted_words) # ['pie', 'apple', 'banana', 'cherry']
# 按字典某个键排序
students = [
{"name": "张三", "score": 85},
{"name": "李四", "score": 92},
{"name": "王五", "score": 78}
]
sorted_students = sorted(students, key=lambda s: s["score"], reverse=True)
# 与map、filter配合
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x**2, numbers))
evens = list(filter(lambda x: x % 2 == 0, numbers))
6. 高阶函数
高阶函数是接收函数作为参数或返回函数的函数。
6.1 函数作为参数
def apply_operation(numbers, operation):
"""对列表中的每个元素应用操作"""
return [operation(n) for n in numbers]
def square(x):
return x ** 2
def double(x):
return x * 2
numbers = [1, 2, 3, 4, 5]
print(apply_operation(numbers, square)) # [1, 4, 9, 16, 25]
print(apply_operation(numbers, double)) # [2, 4, 6, 8, 10]
print(apply_operation(numbers, lambda x: x + 10)) # [11, 12, 13, 14, 15]
6.2 函数作为返回值
def make_multiplier(n):
"""返回一个乘以n的函数"""
def multiplier(x):
return x * n
return multiplier
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
# 实际应用:创建验证器
def make_validator(min_val, max_val):
def validator(x):
return min_val <= x <= max_val
return validator
is_valid_age = make_validator(0, 150)
is_valid_score = make_validator(0, 100)
print(is_valid_age(25)) # True
print(is_valid_score(150)) # False
6.3 内置高阶函数
numbers = [1, 2, 3, 4, 5]
# map:对每个元素应用函数
squares = list(map(lambda x: x**2, numbers))
print(squares) # [1, 4, 9, 16, 25]
# filter:过滤元素
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4]
# reduce:累积计算
from functools import reduce
total = reduce(lambda a, b: a + b, numbers)
print(total) # 15
product = reduce(lambda a, b: a * b, numbers)
print(product) # 120
# 更Pythonic的写法(推荐)
squares = [x**2 for x in numbers]
evens = [x for x in numbers if x % 2 == 0]
total = sum(numbers)
7. 闭包
闭包是引用了外部函数变量的内部函数。
def counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
# 创建计数器
c1 = counter()
c2 = counter()
print(c1()) # 1
print(c1()) # 2
print(c1()) # 3
print(c2()) # 1(独立的计数器)
# 实际应用:缓存
def make_cache():
cache = {}
def cached_func(n):
if n not in cache:
print(f"计算{n}...")
cache[n] = n ** 2
return cache[n]
return cached_func
square = make_cache()
print(square(5)) # 计算5... 25
print(square(5)) # 25(直接返回缓存)
print(square(3)) # 计算3... 9
8. 装饰器入门
装饰器是修改函数行为的函数。
# 基本装饰器
def my_decorator(func):
def wrapper(*args, **kwargs):
print("函数执行前")
result = func(*args, **kwargs)
print("函数执行后")
return result
return wrapper
@my_decorator
def say_hello(name):
print(f"Hello, {name}!")
say_hello("张三")
# 输出:
# 函数执行前
# Hello, 张三!
# 函数执行后
# 等价于
def say_hello(name):
print(f"Hello, {name}!")
say_hello = my_decorator(say_hello)
# 实用装饰器:计时器
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:.4f}秒")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
return "完成"
slow_function()
# 保留原函数信息
from functools import wraps
def my_decorator(func):
@wraps(func) # 保留原函数的__name__和__doc__
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
9. 类型提示(Type Hints)
Python 3.5+支持类型提示,提高代码可读性和IDE支持。
# 基本类型提示
def greet(name: str) -> str:
return f"Hello, {name}!"
def add(a: int, b: int) -> int:
return a + b
# 复杂类型
from typing import List, Dict, Tuple, Optional, Union
def process_numbers(numbers: List[int]) -> int:
return sum(numbers)
def get_user(user_id: int) -> Dict[str, str]:
return {"id": str(user_id), "name": "张三"}
def divide(a: float, b: float) -> Optional[float]:
"""返回除法结果,除数为0时返回None"""
if b == 0:
return None
return a / b
def process(value: Union[int, str]) -> str:
"""接受int或str"""
return str(value)
# 默认参数
def greet(name: str, greeting: str = "Hello") -> str:
return f"{greeting}, {name}!"
# 可变参数
def sum_all(*args: int) -> int:
return sum(args)
# 类型提示不会强制检查,只是提示
result = add("hello", "world") # 运行时不会报错
# 但IDE和类型检查工具(如mypy)会警告
10. 常见错误与避坑
❌ 错误1:可变默认参数
# 错误:使用可变对象作为默认参数
def add_item(item, lst=[]):
lst.append(item)
return lst
print(add_item(1)) # [1]
print(add_item(2)) # [1, 2](不是[2]!)
# 正确:使用None作为默认值
def add_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
❌ 错误2:修改全局变量
# 错误:忘记声明global
counter = 0
def increment():
counter += 1 # UnboundLocalError
# 正确
def increment():
global counter
counter += 1
❌ 错误3:返回值被忽略
# 错误:忽略返回值
def process(data):
return data.upper()
text = "hello"
process(text) # 返回值被忽略
print(text) # 仍然是"hello"
# 正确
text = process(text)
print(text) # "HELLO"
❌ 错误4:参数顺序错误
# 错误:默认参数在非默认参数之前
# def func(a=1, b): # SyntaxError
# pass
# 正确
def func(b, a=1):
pass
11. 实战练习
练习1:实现装饰器
"""
练习:实现一个重试装饰器
"""
import time
from functools import wraps
def retry(max_attempts=3, delay=1):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(1, max_attempts + 1):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"尝试{attempt}失败:{e}")
if attempt < max_attempts:
time.sleep(delay)
raise Exception(f"重试{max_attempts}次后仍然失败")
return wrapper
return decorator
@retry(max_attempts=3, delay=0.5)
def unstable_function():
import random
if random.random() < 0.7:
raise ValueError("随机错误")
return "成功"
# result = unstable_function()
练习2:实现缓存装饰器
"""
练习:实现一个简单的缓存装饰器
"""
from functools import wraps
def cache(func):
cached_results = {}
@wraps(func)
def wrapper(*args):
if args not in cached_results:
cached_results[args] = func(*args)
return cached_results[args]
return wrapper
@cache
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(100)) # 快速计算
练习3:参数验证
"""
练习:实现参数验证函数
"""
def validate_args(**validators):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
# 获取函数参数名
import inspect
sig = inspect.signature(func)
bound = sig.bind(*args, **kwargs)
bound.apply_defaults()
# 验证参数
for param_name, validator in validators.items():
if param_name in bound.arguments:
value = bound.arguments[param_name]
if not validator(value):
raise ValueError(f"参数{param_name}验证失败:{value}")
return func(*args, **kwargs)
return wrapper
return decorator
@validate_args(
age=lambda x: 0 <= x <= 150,
name=lambda x: len(x) > 0
)
def create_user(name, age):
return {"name": name, "age": age}
print(create_user("张三", 25))
# create_user("张三", 200) # ValueError
12. 总结
🔑 核心要点
| 知识点 | 要点 |
|---|---|
| 函数定义 | def关键字,冒号,缩进 |
| 参数类型 | 位置、默认、*args、**kwargs |
| 返回值 | 可返回多个值(元组) |
| 作用域 | LEGB规则,global/nonlocal |
| Lambda | 匿名函数,单行表达式 |
| 高阶函数 | 函数作为参数或返回值 |
| 闭包 | 内部函数引用外部变量 |
| 装饰器 | 修改函数行为 |
| 类型提示 | 提高可读性,IDE支持 |
✅ 学习检查清单
- 掌握函数定义和调用
- 理解各种参数类型
- 掌握返回多个值的方法
- 理解变量作用域和LEGB规则
- 能使用Lambda表达式
- 了解高阶函数的概念
- 理解闭包的原理
- 能编写简单的装饰器
📖 下一步学习
掌握了函数基础后,让我们学习Python的字符串处理:
常见问题 FAQ
💬 Python函数参数是传值还是传引用?
都不是。Python是”传对象引用”。不可变对象(int/str/tuple)表现像传值,可变对象(list/dict)表现像传引用。关键是理解:赋值操作会创建新引用,修改操作会影响原对象。
💬 默认参数用可变对象(如list)会怎样?
这是经典坑!def f(lst=[]):中的默认列表会在多次调用间共享。正确写法是def f(lst=None): lst = lst or []。
� 系列导航
- 上一篇:07 - Python流程控制
- 当前:08 - Python函数基础
- 下一篇:09 - Python字符串处理