Python 函数完全指南:定义与调用
目录
1. 什么是函数?
2. 函数的定义
2.1 基本语法
2.2 带参数的函数
2.3 带返回值的函数
2.4 空函数(占位)
3. 函数的调用
4. 参数类型详解
4.1 位置参数(必须参数)
4.3 关键字参数
4.4 可变长度参数
4.5 参数组合顺序
5. 返回值详解
5.1 单个返回值
5.2 多个返回值(本质是返回元组)
5.3 return 语句省略时返回 None
5.4 return 提前退出函数
6. 作用域
6.1 局部变量与全局变量
6.2 nonlocal 关键字(用于嵌套函数)
7. 函数也是对象
8. 匿名函数(lambda)
9. 递归函数
10. 类型注解(Type Hints)
11. 常见内置函数示例
12.常见陷阱与最佳实践
在编程中,我们经常需要重复执行某段代码。如果每次都复制粘贴,不仅代码冗长,而且修改起来非常麻烦。函数就是解决这个问题的利器:它将一段具有独立功能的代码打包成一个“积木块”,需要时只需“调用”即可。
1. 什么是函数?
函数是一段可重复使用的代码块,它接收输入(参数),进行处理,并可能返回输出(返回值)。函数可以帮你:
避免重复:同样的逻辑只需写一次。
模块化:将复杂程序拆分成小功能块。
易维护:修改函数内部实现,所有调用处自动生效。
Python 内置了很多函数(如print()、len()),你也可以自定义函数。
2. 函数的定义
2.1 基本语法
使用def关键字定义函数,后面跟函数名、括号()和冒号:,函数体缩进。
def function_name(parameters):
"""可选的文档字符串"""
函数体代码
return 返回值 # 可选
eg
def greet(): """打印欢迎信息""" print("Hello, welcome to Python!") # 调用函数 greet()def greet()::def是定义函数的关键字,greet是函数名,空括号表示该函数不接受任何参数,冒号表示函数体开始。"""打印欢迎信息""":这是一个文档字符串(docstring),用三个双引号包围。它是对函数功能的说明,可以通过help(greet)或greet.__doc__查看。虽然不是必需的,但强烈建议添加。print("Hello, welcome to Python!"):这是函数体,缩进表示属于函数的一部分。当函数被调用时,这一行代码会被执行。greet():调用函数,执行函数体内的代码。
2.2 带参数的函数
def greet_person(name): """向指定的人打招呼""" print(f"Hello, {name}!") greet_person("Alice") # Hello, Alice!def greet_person(name)::定义了一个形参name,它将在函数内部作为变量使用。print(f"Hello, {name}!"):函数体内使用了name变量,它的值由调用时传入。greet_person("Alice"):调用时传入实参"Alice",它会被赋值给形参name,因此函数体内输出Hello, Alice!。
2.3 带返回值的函数
使用return语句返回结果。
def add(a, b): """返回两个数的和""" result = a + b return result sum_val = add(3, 5) # 返回 8 print(sum_val)代码解析:
def add(a, b)::定义两个形参a和b。result = a + b:计算两个参数的和,赋值给局部变量result。return result:将result的值返回给调用者。函数执行到return语句时会立即结束,并将返回值传递给调用方。sum_val = add(3, 5):调用add函数,实参3和5分别传给a和b,函数返回8,然后赋值给变量sum_val。print(sum_val):输出8。
2.4 空函数(占位)
如果函数体还未实现,可以用pass占位。
def not_ready(): pass # 稍后实现代码解析:
def not_ready()::定义函数。pass:是一个空语句,什么都不做。语法上需要一个语句,但逻辑上还未实现,用pass避免语法错误。
3. 函数的调用
调用函数就是使用函数名加上括号和实际参数。
# 定义 def multiply(x, y): return x * y # 调用 result = multiply(4, 5) print(result) # 20代码解析:
def multiply(x, y)::定义乘法函数。return x * y:返回两数乘积。result = multiply(4, 5):调用函数,实参4对应x,5对应y,返回值20存入result。print(result):输出20。
调用时的细节:
函数名后面必须跟括号,即使没有参数也要写
()。实参会按照形参的位置一一对应(位置参数)。
调用时传递的实参个数必须与形参个数匹配(除非有默认参数)。
4. 参数类型详解
4.1 位置参数(必须参数)
最普通的形式,调用时按顺序传递。
def greet_with_default(name, greeting="Hello"): print(f"{greeting}, {name}!") greet_with_default("Alice") # Hello, Alice! greet_with_default("Bob", "Hi") # Hi, Bob!代码解析:
greeting="Hello":为greeting参数指定默认值"Hello"。调用时若不提供第二个参数,则使用默认值。greet_with_default("Alice"):只传一个参数,greeting使用默认值"Hello",输出Hello, Alice!。greet_with_default("Bob", "Hi"):传入两个参数,greeting被覆盖为"Hi",输出Hi, Bob!。
注意:默认参数必须放在非默认参数之后。
# 错误写法 def wrong(a=1, b): # SyntaxError pass陷阱:默认参数的值只在函数定义时计算一次,因此不能使用可变对象作为默认值(如列表)。
# 不推荐 def add_item(item, lst=[]): lst.append(item) return lst print(add_item(1)) # [1] print(add_item(2)) # [1, 2] ← 同一个列表被重复使用代码解析:
因为默认参数
lst在函数定义时被创建(一个空列表),之后每次调用若不提供lst,都会使用同一个列表对象,导致累积。解决办法是使用
None作为默认值,然后在函数内部创建新列表。
正确做法:
def add_item(item, lst=None): if lst is None: lst = [] lst.append(item) return lst代码解析:
lst=None:默认值设为不可变对象None。if lst is None: lst = []:每次调用时若未传入列表,则新建一个空列表,保证了独立性。
4.3 关键字参数
调用时通过形参名指定实参,可以改变顺序。
def describe_pet(name, species): print(f"{name} is a {species}") describe_pet(species="cat", name="Tom") # Tom is a cat代码解析:
describe_pet(species="cat", name="Tom"):显式指定每个参数的名字,顺序可以与定义不同。这样调用时不会受位置影响,增强了可读性。
4.4 可变长度参数
*args:接收任意多个位置参数,打包成元组。**kwargs:接收任意多个关键字参数,打包成字典。
def sum_all(*args): return sum(args) print(sum_all(1, 2, 3, 4)) # 10代码解析:
*args:收集所有传入的位置参数为一个元组,这里args是(1,2,3,4)。sum(args):内置函数sum对元组求和,返回10。
def print_info(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}") print_info(name="Alice", age=30, city="Paris")代码解析:
**kwargs:收集所有传入的关键字参数为一个字典,这里kwargs是{'name':'Alice','age':30,'city':'Paris'}。遍历字典并打印。
4.5 参数组合顺序
在函数定义中,参数的顺序必须是:
位置参数
默认参数
*args关键字参数(仅限
*之后)**kwargs
def complex_func(a, b=1, *args, c=2, **kwargs): pass代码解析:
a是普通位置参数。b=1是默认参数。*args接收多余的位置参数。c=2是仅限关键字参数(必须通过关键字传递)。**kwargs接收多余的关键字参数。
5. 返回值详解
5.1 单个返回值
def square(x): return x ** 2代码解析:函数返回x的平方,返回后调用方可以接收。
5.2 多个返回值(本质是返回元组)
def get_stats(numbers): return min(numbers), max(numbers), sum(numbers)/len(numbers) low, high, avg = get_stats([1,2,3,4,5]) print(low, high, avg) # 1 5 3.0代码解析:
return min(...), max(...), avg(...):实际上返回了一个元组(min, max, avg)。调用方通过
low, high, avg = ...进行拆包,分别接收三个值。
5.3return语句省略时返回None
def do_nothing(): pass print(do_nothing()) # None代码解析:函数没有显式return,默认返回None。
5.4return提前退出函数
def is_positive(n): if n > 0: return True return False代码解析:
如果
n > 0,执行return True,函数立即结束,不会执行后面的return False。否则执行
return False。这种写法可避免使用else。
6. 作用域
6.1 局部变量与全局变量
在函数内部赋值的变量是局部变量,只在函数内有效。
在函数外部定义的变量是全局变量,可在函数内读取,但若要修改需用
global关键字。
x = 10 # 全局变量 def func(): global x # 声明要修改全局变量 x = 20 y = 5 # 局部变量 func() print(x) # 20代码解析:
x = 10:全局变量。def func():内部global x:告诉 Python 这里的x是全局变量,而不是创建局部变量。x = 20:修改全局x的值为 20。y = 5:未声明global,因此是局部变量,函数外部无法访问。调用
func()后,全局x变为 20。
注意:避免过多使用global,推荐通过参数传递和返回值来通信。
6.2nonlocal关键字(用于嵌套函数)
在内层函数中修改外层函数(非全局)的变量。
def outer(): count = 0 def inner(): nonlocal count count += 1 return count return inner counter = outer() print(counter()) # 1 print(counter()) # 2代码解析:
outer函数中定义了局部变量count和内层函数inner。inner中使用nonlocal count声明要修改的是外层函数outer的count变量,而不是创建一个新的局部变量。count += 1修改外层变量。outer返回inner函数对象,形成一个闭包。每次调用counter()都会增加并返回count的值。
7. 函数也是对象
在 Python 中,函数是一等公民,可以赋值给变量、作为参数传递、作为返回值。
def add(a, b): return a + b my_func = add # 赋值 print(my_func(3, 4)) # 7代码解析:将函数add赋值给变量my_func,my_func现在指向同一个函数对象,可以像add一样调用。
def apply(func, x, y): return func(x, y) print(apply(add, 5, 6)) # 11代码解析:apply函数接收一个函数作为参数func,然后在内部调用它。这体现了高阶函数的特性。
8. 匿名函数(lambda)
lambda表达式用于创建简单的、单表达式的匿名函数。
square = lambda x: x ** 2 print(square(5)) # 25代码解析:
lambda x: x ** 2定义了一个匿名函数,等价于def square(x): return x**2。但
lambda只能包含一个表达式,不能包含语句。
# 常用于 sort 的 key 参数 pairs = [(1, 'one'), (2, 'two'), (3, 'three')] pairs.sort(key=lambda pair: pair[1]) # 按字符串排序代码解析:sort的key参数接收一个函数,用于从每个元素中提取比较键。这里用lambda取每个元组的第二个元素(字符串)作为排序依据。
限制:lambda 只能有一个表达式,不能包含语句(如print、return等)。
9. 递归函数
函数调用自身称为递归。需要明确的终止条件。
def factorial(n): if n <= 1: return 1 return n * factorial(n - 1) print(factorial(5)) # 120代码解析:
if n <= 1: return 1:递归的终止条件,防止无限递归。return n * factorial(n-1):递归调用,每次减少n的值。调用过程:
factorial(5)→5 * factorial(4)→5 * 4 * factorial(3)→ ... →5 * 4 * 3 * 2 * 1。
注意:Python 递归深度有限制(默认约 1000),深层递归建议改用循环。
10. 类型注解(Type Hints)
Python 3.5+ 支持类型注解,提高代码可读性(不强制检查)。
def greet(name: str) -> str: return f"Hello, {name}"代码解析:
name: str:表示参数name应为字符串类型。-> str:表示返回值应为字符串类型。这些注解只是提示,不会在运行时检查类型错误。可以用
mypy工具进行静态类型检查。
11. 常见内置函数示例
print():输出len():返回长度type():返回类型input():读取用户输入range():生成整数序列sum()、max()、min()等
这些内置函数无需定义,直接使用。
12.常见陷阱与最佳实践
| 陷阱 | 说明 | 解决方案 |
|---|---|---|
| 使用可变对象作为默认参数 | 函数多次调用共享同一对象 | 使用None并在函数内创建新对象 |
| 在函数内修改全局变量未声明 | 会创建同名局部变量 | 使用global或通过参数/返回值传递 |
| 混淆位置参数和关键字参数 | 调用时顺序错误 | 明确指定关键字参数名 |
| 递归深度过大导致栈溢出 | 递归超过系统限制 | 改用循环或增加sys.setrecursionlimit |
忘记return导致返回None | 预期有返回值但实际为None | 检查函数所有分支是否都有return |
lambda内使用复杂逻辑 | 无法使用语句,代码难读 | 改用普通函数 |
感谢你的观看,期待我们下次再见!
