1. Python函数基础:从零开始理解函数
Python函数就像现实世界中的工具包,把一系列操作打包成一个独立单元,随时调用。想象你有一个早餐机,放入面包和鸡蛋(输入参数),按下按钮(调用函数),就能得到美味的三明治(返回值)。这种封装思想是编程的核心。
1.1 函数定义与调用的本质
定义函数使用def关键字,这是Python的固定语法:
python复制def 函数名(参数):
# 函数体
操作步骤
return 返回值
来看一个真实案例:电商网站的用户欢迎功能。每次新用户注册时,都需要显示欢迎信息。没有函数时,代码会重复出现:
python复制# 没有函数的写法
username = "张三"
print(f"欢迎{username}加入我们的商城!")
print("您已获得新人礼包")
print("请完成邮箱验证")
username = "李四"
print(f"欢迎{username}加入我们的商城!")
print("您已获得新人礼包")
print("请完成邮箱验证")
使用函数后:
python复制def welcome_user(name):
print(f"欢迎{name}加入我们的商城!")
print("您已获得新人礼包")
print("请完成邮箱验证")
welcome_user("张三")
welcome_user("李四")
关键经验:当同一段代码出现超过两次,就应该考虑封装成函数。这符合DRY(Don't Repeat Yourself)原则。
1.2 函数参数详解
参数是函数与外界沟通的桥梁。Python支持多种参数传递方式:
位置参数(Positional Arguments)
最常见的参数形式,按顺序一一对应:
python复制def calculate_bmi(weight, height):
return weight / (height ** 2)
# 必须按顺序传参
bmi = calculate_bmi(70, 1.75) # 正确
bmi = calculate_bmi(1.75, 70) # 错误!计算结果完全不对
关键字参数(Keyword Arguments)
通过参数名指定值,顺序不重要:
python复制bmi = calculate_bmi(height=1.75, weight=70) # 明确指定参数名
实际开发建议:当函数有超过3个参数时,推荐使用关键字参数,提高可读性。
默认参数(Default Arguments)
为参数提供默认值,调用时可省略:
python复制def create_user(name, age, gender='未知', vip=False):
print(f"创建用户:{name},年龄:{age},性别:{gender},VIP:{vip}")
create_user("王五", 25) # 使用默认gender和vip
create_user("赵六", 30, vip=True) # 只覆盖vip参数
默认参数陷阱:默认值只会在函数定义时计算一次,对于可变对象(如列表、字典)会导致意外行为:
python复制# 错误示范
def add_item(item, items=[]):
items.append(item)
return items
print(add_item(1)) # [1]
print(add_item(2)) # [1, 2] 不是预期的[2]!
# 正确写法
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
2. 高级参数处理技巧
2.1 可变参数:*args和**kwargs
当参数数量不确定时,Python提供了灵活的解决方案:
*args 接收任意数量的位置参数
python复制def sum_numbers(*args):
print(f"参数类型:{type(args)}") # 总是元组
return sum(args)
print(sum_numbers(1, 2, 3)) # 6
print(sum_numbers(10, 20, 30, 40, 50)) # 150
典型应用场景:数学计算、日志记录等需要处理不定量数据的场合。
**kwargs 接收任意数量的关键字参数
python复制def build_profile(**kwargs):
profile = {}
for key, value in kwargs.items():
profile[key] = value
return profile
user = build_profile(name="小明", age=18, hobby=["篮球", "编程"])
print(user) # {'name': '小明', 'age': 18, 'hobby': ['篮球', '编程']}
常见用途:配置初始化、API参数传递等需要键值对的场景。
2.2 参数组合使用规则
Python对参数顺序有严格要求:
- 位置参数
- *args
- 关键字参数
- **kwargs
python复制def complex_func(a, b, *args, option=True, **kwargs):
print(f"a={a}, b={b}")
print(f"args={args}")
print(f"option={option}")
print(f"kwargs={kwargs}")
complex_func(1, 2, 3, 4, option=False, x=10, y=20)
# 输出:
# a=1, b=2
# args=(3, 4)
# option=False
# kwargs={'x': 10, 'y': 20}
调试技巧:当参数传递出现问题时,先检查参数顺序是否符合规范。
3. 返回值与作用域深度解析
3.1 返回值的多种形式
函数通过return语句返回结果,没有return或return None时返回None。
返回多个值(实际是返回元组)
python复制def analyze_text(text):
words = text.split()
word_count = len(words)
char_count = len(text)
return word_count, char_count # 实际上是返回一个元组
stats = analyze_text("Python是一种优雅的编程语言")
print(stats) # (6, 15) 中文分词可能不准确,仅作示例
提前返回
函数可以在任何位置使用return提前结束:
python复制def find_first_even(numbers):
for num in numbers:
if num % 2 == 0:
return num # 找到第一个偶数立即返回
return None # 没找到返回None
print(find_first_even([1, 3, 5, 7, 8, 9])) # 8
3.2 变量作用域详解
Python有四种作用域:
- 局部(Local) - 函数内部
- 嵌套(Enclosing) - 闭包函数外层
- 全局(Global) - 模块级别
- 内置(Built-in) - Python内置名称
python复制x = "global" # 全局变量
def outer():
x = "outer" # 嵌套作用域
def inner():
x = "inner" # 局部变量
print(x) # inner
inner()
print(x) # outer
outer()
print(x) # global
global和nonlocal关键字
修改全局变量需要使用global声明:
python复制count = 0
def increment():
global count
count += 1
print(count)
increment() # 1
increment() # 2
对于嵌套函数,要修改外层变量需要使用nonlocal:
python复制def counter():
num = 0
def increment():
nonlocal num
num += 1
return num
return increment
c = counter()
print(c()) # 1
print(c()) # 2
最佳实践:尽量减少使用global,优先通过参数传递和返回值来交换数据,这样代码更清晰、更易维护。
4. 函数高级技巧与最佳实践
4.1 文档字符串(Docstring)
良好的文档是代码可维护性的关键。Python使用三引号字符串作为函数文档:
python复制def calculate_tax(income, rate=0.1):
"""
计算应缴税款
参数:
income (float): 年收入,必须为正数
rate (float): 税率,默认为0.1(10%)
返回:
float: 计算结果,保留两位小数
异常:
ValueError: 当收入为负数时抛出
示例:
>>> calculate_tax(50000)
5000.0
"""
if income < 0:
raise ValueError("收入不能为负数")
return round(income * rate, 2)
可以通过__doc__属性或help()函数查看文档:
python复制print(calculate_tax.__doc__)
help(calculate_tax)
4.2 Lambda匿名函数
Lambda用于创建小型匿名函数,适合简单操作:
python复制# 普通函数
def square(x):
return x * x
# Lambda等价形式
square = lambda x: x * x
# 常用场景:排序
students = [
{"name": "张三", "score": 88},
{"name": "李四", "score": 76},
{"name": "王五", "score": 92}
]
# 按分数降序排序
students.sort(key=lambda s: s["score"], reverse=True)
print(students)
使用建议:Lambda适合简单表达式,复杂逻辑还是应该使用def定义常规函数。
4.3 函数作为一等公民
Python中函数是对象,可以像其他对象一样被传递和使用:
python复制def apply_operation(func, x, y):
return func(x, y)
def add(a, b):
return a + b
def multiply(a, b):
return a * b
print(apply_operation(add, 3, 4)) # 7
print(apply_operation(multiply, 3, 4)) # 12
这种特性使得Python非常适合函数式编程风格。
5. 常见问题与调试技巧
5.1 参数传递错误
python复制def divide(a, b):
return a / b
# 常见错误1:参数数量不对
divide(10) # TypeError: divide() missing 1 required positional argument: 'b'
# 常见错误2:参数顺序不对
divide(b=10, a=20) # 正确,关键字参数顺序不重要
divide(10, b=20) # 正确
divide(a=10, 20) # 错误!位置参数不能在关键字参数后
5.2 变量作用域混淆
python复制x = 10
def confuse():
print(x) # 这里会报错!
x = 20
confuse() # UnboundLocalError: local variable 'x' referenced before assignment
这是因为Python在函数中发现有对x的赋值操作,就把x当作局部变量,但print时x还未定义。
解决方法:
python复制x = 10
def clear():
global x
print(x) # 10
x = 20
clear()
5.3 可变默认参数陷阱再强调
这是Python新手最容易犯的错误之一:
python复制# 危险代码!
def append_to(element, target=[]):
target.append(element)
return target
print(append_to(1)) # [1]
print(append_to(2)) # [1, 2] 不是预期的[2]!
正确做法:
python复制def append_to(element, target=None):
if target is None:
target = []
target.append(element)
return target
6. 实战案例:构建一个简单的购物车系统
让我们用所学的函数知识实现一个购物车:
python复制def create_cart():
"""创建一个新的购物车"""
return {"items": [], "total": 0.0}
def add_item(cart, name, price, quantity=1):
"""向购物车添加商品"""
cart["items"].append({
"name": name,
"price": price,
"quantity": quantity
})
cart["total"] += price * quantity
def remove_item(cart, name):
"""从购物车移除商品"""
for item in cart["items"]:
if item["name"] == name:
cart["total"] -= item["price"] * item["quantity"]
cart["items"].remove(item)
return True
return False
def apply_discount(cart, discount_rate):
"""应用折扣"""
if 0 < discount_rate < 1:
cart["total"] *= (1 - discount_rate)
return True
return False
def print_receipt(cart):
"""打印购物小票"""
print("=== 购物清单 ===")
for item in cart["items"]:
print(f"{item['name']} x{item['quantity']}: ¥{item['price'] * item['quantity']:.2f}")
print("================")
print(f"总计: ¥{cart['total']:.2f}")
# 使用示例
my_cart = create_cart()
add_item(my_cart, "Python书", 99.0)
add_item(my_cart, "鼠标", 159.0, 2)
apply_discount(my_cart, 0.1)
print_receipt(my_cart)
这个案例展示了如何用函数组织代码,每个函数只做一件事,通过参数和返回值交换数据,这正是函数式编程的核心思想。