1. 函数介绍
函数是Python中组织代码的核心结构,用于封装可重用的逻辑。除了内置函数(如print()、len()),我们还可以通过def语句自定义函数,实现代码模块化与复用。以下是关于函数的详细说明,包含核心概念、示例及扩展知识。
2. 函数的定义与调用
函数通过def语句定义,基本语法为:
def 函数名(参数列表):
函数体(缩进代码块)
[return 返回值]核心特点:
- 函数体必须缩进(通常 4 个空格),以区分函数内外代码。
- 函数必须先定义后调用,否则会触发NameError。
- 函数体仅在调用时执行。
示例:定义一个无参数函数,打印指定内容
# 定义函数
def greet():
"""打印问候语三次"""
for _ in range(3):
print("你好,Loen")
# 调用函数(必须在定义之后)
greet()
# 输出:
# 你好,Loen
# 你好,Loen
# 你好,Loen3. 函数参数
参数是函数与外部交互的接口,用于向函数传递数据。根据使用方式,参数可分为多种类型。
3.1 形参与实参
- 形参(形式参数):函数定义时括号内的变量(如name),仅在函数内部有效。
- 实参(实际参数):函数调用时传递给形参的具体值(如”Alice”)。
示例:形参与实参
def say_hello(name): # name 是形参
print(f"你好,{name}!")
say_hello("Alice") # "Alice" 是实参
# 输出:你好,Alice!3.2 多参数与参数顺序
多个参数用逗号分隔,调用时实参顺序需与形参一致(位置参数)。
示例:多参数函数
def introduce(name, age):
print(f"我叫{name},今年{age}岁。")
introduce("Bob", 18) # 按顺序传递实参
# 输出:我叫Bob,今年18岁。3.3 关键字参数
调用函数时,可通过形参名=值的形式指定参数,无需严格遵循顺序,增强代码可读性。
示例:关键字参数
introduce(age=20, name="Charlie") # 用关键字指定参数
# 输出:我叫Charlie,今年20岁。3.4 默认参数
定义函数时,可为形参设置默认值(形参=默认值)。调用时若不传递该参数,则使用默认值。注意:默认参数必须放在非默认参数之后。
示例:默认参数
def order_drink(drink, sugar="正常糖"): # sugar 是默认参数
print(f"点一杯{drink},{sugar}。")
order_drink("奶茶") # 不传递sugar,使用默认值
# 输出:点一杯奶茶,正常糖。
order_drink("咖啡", "少糖") # 传递sugar,覆盖默认值
# 输出:点一杯咖啡,少糖。坑点:默认参数不应设为可变对象(如列表、字典),否则可能导致意外结果:
# 错误示例:默认参数为可变对象
def add_item(item, items=[]):
items.append(item)
return items
print(add_item("苹果")) # 输出:['苹果']
print(add_item("香蕉")) # 输出:['苹果', '香蕉'](意外保留了之前的结果)正确做法:默认值设为None,在函数内初始化可变对象:
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
print(add_item("苹果")) # 输出:['苹果']
print(add_item("香蕉")) # 输出:['香蕉'](符合预期)4. 可变参数(收集参数)
当参数数量不确定时,可使用args和*kwargs收集参数:
- *args:收集所有位置参数,打包为元组(tuple)。
- **kwargs:收集所有关键字参数,打包为字典(dict)。
示例1:args收集位置参数
def sum_numbers(*args):
print("收集的参数:", args) # args 是元组
return sum(args)
print(sum_numbers(1, 2, 3)) # 传递3个位置参数
# 输出:
# 收集的参数: (1, 2, 3)
# 6
print(sum_numbers(10, 20)) # 传递2个位置参数
# 输出:
# 收集的参数: (10, 20)
# 30示例2:kwargs收集关键字参数
def print_info(**kwargs):
print("收集的参数:", kwargs) # kwargs 是字典
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Diana", age=22, city="Beijing")
# 输出:
# 收集的参数: {'name': 'Diana', 'age': 22, 'city': 'Beijing'}
# name: Diana
# age: 22
# city: Beijing组合使用:args必须在**kwargs之前,且普通参数需放在最前:
def func(a, b, *args, **kwargs):
print(f"普通参数:a={a}, b={b}")
print(f"位置参数集合:{args}")
print(f"关键字参数集合:{kwargs}")
func(1, 2, 3, 4, x=5, y=6)
# 输出:
# 普通参数:a=1, b=2
# 位置参数集合:(3, 4)
# 关键字参数集合:{'x': 5, 'y': 6}5. 参数解包
与args/kwargs相反,可通过和将序列或字典解包为参数:
- *序列:将序列(列表、元组等)解包为位置参数。
- **字典:将字典解包为关键字参数。
示例:参数解包
def func(a, b, c):
print(a + b + c)
# 解包列表为位置参数
nums = [1, 2, 3]
func(*nums) # 等价于 func(1, 2, 3)
# 输出:6
# 解包字典为关键字参数
info = {"a": 10, "b": 20, "c": 30}
func(** info) # 等价于 func(a=10, b=20, c=30)
# 输出:606. 参数传递的本质
Python中参数传递是 “传对象引用”:
- 若传递不可变对象(如整数、字符串、元组),函数内修改不会影响外部。
- 若传递可变对象(如列表、字典),函数内修改会影响外部。
示例:参数传递与对象可变性
# 不可变对象(整数)
def modify_int(x):
x = 100 # 重新赋值,不影响外部
print("函数内x:", x)
num = 10
modify_int(num)
print("函数外num:", num)
# 输出:
# 函数内x: 100
# 函数外num: 10
# 可变对象(列表)
def modify_list(lst):
lst.append(4) # 修改原列表,影响外部
print("函数内列表:", lst)
my_list = [1, 2, 3]
modify_list(my_list)
print("函数外列表:", my_list)
# 输出:
# 函数内列表: [1, 2, 3, 4]
# 函数外列表: [1, 2, 3, 4]7. 函数返回值
函数通过return语句返回结果,调用者可接收并使用该结果。
核心特点:
- return后可跟任意类型的值(或表达式)。
- 函数若未显式写return,默认返回None。
- return会立即终止函数执行,后续代码不再运行。
- 可返回多个值(本质是返回元组,调用时可解包)。
示例1:基本返回值
def add(a, b):
return a + b # 返回计算结果
result = add(3, 5)
print(result) # 输出:8示例2:return终止函数
def check_positive(n):
if n > 0:
return "正数"
print("这句不会执行(若n>0)") # return 后代码不执行
print(check_positive(5)) # 输出:正数示例3:返回多个值
def get_user():
name = "Eve"
age = 25
return name, age # 等价于 return (name, age)
user_name, user_age = get_user() # 解包返回值
print(user_name, user_age) # 输出:Eve 258. 函数的注释与文档字符串
注释用于解释代码逻辑,文档字符串(docstring)用于描述函数功能,可通过help()函数查看。
- 单行注释:用#开头,仅注释单行。
- 文档字符串:用”””或”””包裹,可跨多行,通常放在函数定义的第一行。
示例:注释与文档字符串
def calculate_area(radius):
"""
计算圆的面积。
参数:
radius (float): 圆的半径(必须为正数)。
返回:
float: 圆的面积(π * radius²)。
异常:
ValueError: 若半径为负数或零,抛出异常。
"""
if radius <= 0:
raise ValueError("半径必须为正数")
import math
return math.pi * radius ** 2 # 计算面积
# 查看文档字符串
help(calculate_area)
# 输出:
# Help on function calculate_area in module __main__:
# calculate_area(radius)
# 计算圆的面积。
#
# 参数:
# radius (float): 圆的半径(必须为正数)。
#
# 返回:
# float: 圆的面积(π * radius²)。
#
# 异常:
# ValueError: 若半径为负数或零,抛出异常。9. 函数对象特性
在Python中,函数是 “一等公民”,可像其他数据类型一样被操作:
- 赋值给变量。
- 作为参数传递给其他函数。
- 作为返回值从函数中返回。
示例1:函数赋值给变量
def multiply(a, b):
return a * b
func_var = multiply # 函数赋值给变量
print(func_var(3, 4)) # 通过变量调用函数,输出:12示例2:函数作为参数传递
def apply_func(func, x, y):
"""将函数func应用于x和y"""
return func(x, y)
# 传递内置函数max
print(apply_func(max, 5, 10)) # 输出:10
# 传递自定义函数multiply
print(apply_func(multiply, 5, 10)) # 输出:50示例3:函数作为返回值
def make_adder(n):
"""返回一个“累加n”的函数"""
def adder(x):
return x + n
return adder # 返回内部定义的函数
add_5 = make_adder(5) # 获取“加5”的函数
print(add_5(3)) # 输出:8(3+5)
add_10 = make_adder(10)
print(add_10(3)) # 输出:13(3+10)10. 变量作用域
变量的作用域指其可被访问的范围,分为:
- 局部变量:函数内部定义的变量,仅在函数内有效。
- 全局变量:函数外部定义的变量,可在整个模块中访问。
- 嵌套作用域:嵌套函数中,外层函数的变量对内存函数可见(非全局)。
10.1 局部变量与全局变量
# 全局变量
global_var = "我是全局变量"
def my_func():
# 局部变量(仅在函数内有效)
local_var = "我是局部变量"
print(local_var)
print(global_var) # 可访问全局变量
my_func()
# 输出:
# 我是局部变量
# 我是全局变量
print(global_var) # 可访问全局变量
# print(local_var) # 报错:NameError(局部变量在外部不可见)10.2 修改全局变量:global关键字
函数内默认不能修改全局变量(会被视为定义局部变量),需用global声明。
示例:修改全局变量
count = 0 # 全局变量
def increment():
global count # 声明count是全局变量
count += 1 # 修改全局变量
increment()
print(count) # 输出:1
increment()
print(count) # 输出:210.2 修改嵌套作用域变量:nonlocal关键字
在嵌套函数中,若需修改外层函数的变量(非全局),需用nonlocal声明。
示例:嵌套函数与nonlocal
def outer():
x = 10 # 外层函数的变量(嵌套作用域)
def inner():
nonlocal x # 声明x是外层函数的变量
x += 5 # 修改外层变量
print("inner中的x:", x)
inner()
print("outer中的x:", x) # 外层变量已被修改
outer()
# 输出:
# inner中的x: 15
# outer中的x: 1511. 变量作用域嵌套函数
函数内部可定义另一个函数(嵌套函数),内部函数可访问外层函数的变量(闭包特性)。
示例:嵌套函数
def outer_func(message):
def inner_func():
# 内部函数可访问外层函数的参数
print(f"内部函数:{message}")
inner_func() # 外层函数调用内部函数
outer_func("Hello, 嵌套函数!")
# 输出:内部函数:Hello, 嵌套函数!12. 总结
函数是Python代码组织的核心,掌握函数的定义、参数、返回值、作用域等特性,能大幅提升代码的可读性、复用性和可维护性。灵活运用函数对象特性(如作为参数、返回值),还能实现高阶编程模式(如装饰器、闭包),为复杂逻辑提供简洁解决方案。