Python 基础语法 3:函数定义与调用
上一篇我们学会了 “if 判断” 和 “循环”—— 能写出有逻辑的代码了,但如果遇到 “需要重复用某段代码” 的场景(比如多次计算长方形面积、反复验证用户输入),每次都复制粘贴会很麻烦。而 “函数” 就是解决这个问题的 “神器”:把常用代码封装成 “可重复调用的工具”,用的时候喊个名字就能用,不用重复写。今天用生活案例讲透函数的定义、调用、参数和返回值,新手也能快速上手。
一、先搞懂:什么是函数?用生活案例类比
生活中到处都是 “函数” 的影子:
- 计算器:你输入 “数字 + 运算”(比如 3+5),它返回结果(8)—— 这是 “有输入、有输出的函数”;
- 洗衣机:你按下 “启动键”(不用输入额外内容),它自动完成 “加水→洗衣→脱水”(不用管中间步骤)—— 这是 “无输入、有动作的函数”;
- 手电筒:你按 “开关”(输入 “开 / 关”),它执行 “亮 / 灭”(有输入、有动作无返回)—— 这是 “有输入、无输出的函数”。
在 Python 里,函数就是 “一段封装好的代码块”,具有 3 个核心特点:
- 可重复调用:定义一次,后续想用时直接喊函数名,不用重复写代码;
- 可接收输入:根据需要给函数传 “原材料”(参数),让函数处理不同数据;
- 可返回结果:函数处理完后,能把结果 “交回来”(返回值),供后续代码使用。
二、函数的基础用法:定义→调用(两步搞定)
用函数的核心流程只有两步:先定义(造工具)→再调用(用工具)。就像先造一台计算器(定义函数),之后每次算东西都用这台计算器(调用函数)。
1. 第一步:定义函数(造工具)
语法格式(注意缩进!):
|
def 函数名(参数列表): # def是“定义函数”的关键字,参数列表可空(没原材料) """函数说明文档(可选,用来解释函数作用,按Ctrl+Q能看到)""" 函数体 # 要封装的代码(必须缩进,推荐4个空格) return 返回值 # 可选,用来返回处理结果(没返回值时可省略) |
关键规则:
- 函数名:和变量名规则一样(字母 / 数字 / 下划线,不数字开头,见名知意),推荐用 “蛇形命名法”(比如calculate_area、greet_user);
- 参数列表:如果函数需要 “原材料”,就写在这里(多个参数用逗号分隔),不需要就空着(括号不能省);
- 函数说明文档:用三引号包裹,说明函数作用、参数含义、返回值,新手也要养成写的习惯,方便后续自己看;
- return:如果需要函数 “交结果”,就用return,没写的话函数默认返回None(空值)。
案例 1:定义一个 “打招呼” 的函数(无参数、无返回值)
比如每次运行都打印 “你好,欢迎学习 Python!”,不用传参数,也不用返回结果:
|
def greet(): """无参数,无返回值,功能:打印打招呼信息""" print("你好,欢迎学习Python!") print("今天也要加油呀~") # 函数体可以有多行代码 |
案例 2:定义一个 “计算长方形面积” 的函数(有参数、有返回值)
需要传入 “长” 和 “宽”(参数),计算后返回面积(返回值):
|
def calculate_rect_area(length, width): """ 计算长方形面积 参数: length: 长方形的长(数值型) width: 长方形的宽(数值型) 返回值: area: 长方形的面积(length * width) """ area = length * width # 函数体:计算面积 return area # 返回结果(把area交给调用者) |
2. 第二步:调用函数(用工具)
定义好函数后,想用时直接写 “函数名 (参数)” 即可,就像按计算器的 “计算键”。
案例 1:调用 “打招呼” 函数(无参数)
无参数的函数,调用时括号里什么都不用写:
|
# 调用greet函数(执行函数体里的打印代码) greet() # 可以重复调用,不用再写print语句 greet() |
运行结果:
|
你好,欢迎学习Python! 今天也要加油呀~ 你好,欢迎学习Python! 今天也要加油呀~ |
案例 2:调用 “计算长方形面积” 函数(有参数、接收返回值)
有参数的函数,调用时要传对应参数,返回值可以用变量接收:
|
# 调用函数,传入长=5,宽=3,用变量area1接收返回值 area1 = calculate_rect_area(5, 3) print(f"长方形1的面积:{area1}") # 输出:长方形1的面积:15 # 重复调用,传入不同参数(长=10,宽=4) area2 = calculate_rect_area(10, 4) print(f"长方形2的面积:{area2}") # 输出:长方形2的面积:40 |
注意:函数必须 “先定义,再调用”
Python 代码是 “从上到下顺序执行” 的,如果先调用再定义,会报错 “函数未定义”:
|
# 错误示例:调用在定义前面 greet() # 报错:NameError: name 'greet' is not defined def greet(): print("你好") |
三、函数的参数:给函数传 “原材料”(重点)
参数是函数的 “原材料入口”,不同场景需要传不同类型的参数。Python 里最常用的参数类型有 4 种:位置参数、关键字参数、默认参数、不定长参数,逐个拆解。
1. 位置参数:按 “顺序” 传参(最基础)
调用函数时,参数的 “顺序” 必须和定义时一致,个数也要对应,否则会算错或报错。
案例:定义一个 “计算两数之和与差” 的函数
|
def calculate_sum_diff(a, b): """ 计算两数的和与差 参数: a: 第一个数(位置参数1) b: 第二个数(位置参数2) 返回值: sum_ab: 和(a + b) diff_ab: 差(a - b) """ sum_ab = a + b diff_ab = a - b return sum_ab, diff_ab # 函数可以返回多个值,用逗号分隔 |
调用时按顺序传参:
|
# 位置参数:a=10,b=5(顺序不能乱) sum_result, diff_result = calculate_sum_diff(10, 5) print(f"和:{sum_result},差:{diff_result}") # 输出:和:15,差:5 # 错误示例1:顺序传反(a=5,b=10),结果错了 sum_wrong, diff_wrong = calculate_sum_diff(5, 10) print(f"错误和:{sum_wrong},错误差:{diff_wrong}") # 输出:错误和:15,错误差:-5 # 错误示例2:参数个数不匹配(少传1个) # calculate_sum_diff(10) # 报错:TypeError: calculate_sum_diff() missing 1 required positional argument: 'b' |
2. 关键字参数:按 “名字” 传参(不怕顺序乱)
调用函数时,明确指定 “参数名 = 值”,这样不用记顺序,适合参数多的场景。
案例:调用上面的calculate_sum_diff函数
|
# 关键字参数:明确a=10,b=5,顺序可以换 sum1, diff1 = calculate_sum_diff(a=10, b=5) print(f"关键字传参1:和={sum1},差={diff1}") # 输出:和=15,差=5 # 顺序换了也没问题(因为指定了参数名) sum2, diff2 = calculate_sum_diff(b=5, a=10) print(f"关键字传参2:和={sum2},差={diff2}") # 输出:和=15,差=5 |
混合使用:位置参数在前,关键字参数在后
可以先传位置参数,再传关键字参数,但位置参数不能在关键字参数后面:
|
# 正确:先位置参数a=10,再关键字参数b=5 sum3, diff3 = calculate_sum_diff(10, b=5) print(f"混合传参:和={sum3},差={diff3}") # 输出:和=15,差=5 # 错误:位置参数在关键字参数后面 # calculate_sum_diff(a=10, 5) # 报错:SyntaxError: positional argument follows keyword argument |
3. 默认参数:给参数设 “默认值”(调用时可省)
定义函数时,给参数设置 “默认值”,调用时如果不传这个参数,就用默认值;传了就用新值。适合 “大部分情况用默认值,偶尔需要改” 的场景。
案例:定义一个 “计算折扣价” 的函数
比如大部分商品打 95 折(默认折扣 0.95),VIP 客户打 8 折(传折扣 0.8):
|
def calculate_discount_price(original_price, discount=0.95): """ 计算商品折扣价 参数: original_price: 原价(必须传,无默认值) discount: 折扣(默认0.95,可选传) 返回值: discount_price: 折扣价(原价 * 折扣) """ discount_price = original_price * discount return discount_price |
调用时的 3 种情况:
|
# 情况1:只传原价(用默认折扣0.95) price1 = calculate_discount_price(100) # 原价100,折扣0.95 print(f"普通客户价:{price1}元") # 输出:普通客户价:95.0元 # 情况2:传原价和折扣(覆盖默认值) price2 = calculate_discount_price(100, 0.8) # 原价100,折扣0.8 print(f"VIP客户价1:{price2}元") # 输出:VIP客户价1:80.0元 # 情况3:用关键字参数传折扣(更清晰) price3 = calculate_discount_price(original_price=100, discount=0.7) print(f"VIP客户价2:{price3}元") # 输出:VIP客户价2:70.0元 |
注意:默认参数要放在 “非默认参数后面”
定义函数时,有默认值的参数必须在没默认值的参数后面,否则报错:
|
# 错误示例:默认参数在非默认参数前面 # def calculate_discount_price(discount=0.95, original_price): # 报错:SyntaxError: non-default argument follows default argument |
4. 不定长参数:接收 “不确定个数” 的参数(灵活)
如果不知道要传多少个参数(比如计算 “任意多个数的总和”),用不定长参数:*args(接收多个位置参数,存成元组)和**kwargs(接收多个关键字参数,存成字典)。
案例 1:用*args计算任意多个数的总和
|
def calculate_total(*args): """ 计算任意多个数的总和 参数: *args: 不定长位置参数(接收多个数值,存成元组) 返回值: total: 所有数的总和 """ print(f"接收的参数:{args}") # 查看args的类型(元组) total = sum(args) # sum()是Python内置函数,能直接求和 return total |
调用时传任意个数的参数:
|
# 传2个数 total1 = calculate_total(10, 20) print(f"2个数的和:{total1}") # 输出:接收的参数:(10, 20),2个数的和:30 # 传5个数 total2 = calculate_total(1, 2, 3, 4, 5) print(f"5个数的和:{total2}") # 输出:接收的参数:(1, 2, 3, 4, 5),5个数的和:15 # 传列表(需要在列表前加*,把列表元素拆成位置参数) num_list = [100, 200, 300] total3 = calculate_total(*num_list) print(f"列表元素的和:{total3}") # 输出:接收的参数:(100, 200, 300),列表元素的和:600 |
案例 2:用**kwargs接收任意多个关键字参数
比如处理用户的 “个人信息”,可能有姓名、年龄、电话等不确定的字段:
|
def print_user_info(**kwargs): """ 打印用户的任意个人信息 参数: **kwargs: 不定长关键字参数(接收多个键值对,存成字典) """ print(f"用户信息(字典):{kwargs}") # 查看kwargs的类型(字典) for key, value in kwargs.items(): # 遍历字典,打印每个字段 print(f"{key}:{value}") |
调用时传任意个关键字参数:
|
# 传2个关键字参数 print_user_info(name="小明", age=18) # 输出: # 用户信息(字典):{'name': '小明', 'age': 18} # name:小明 # age:18 # 传3个关键字参数 print_user_info(name="小红", age=20, phone="13812345678") # 输出: # 用户信息(字典):{'name': '小红', 'age': 20, 'phone': '13812345678'} # name:小红 # age:20 # phone:13812345678 # 传字典(需要在字典前加**,把字典拆成关键字参数) user_dict = {"name": "小刚", "age": 19, "address": "北京"} print_user_info(**user_dict) # 输出: # 用户信息(字典):{'name': '小刚', 'age': 19, 'address': '北京'} # name:小刚 # age:19 # address:北京 |
四、函数的返回值:让函数 “交结果”(return 用法)
返回值是函数处理后的 “输出”,用return关键字实现。新手要注意 3 个核心点:return的作用、返回多个值、return后的代码不执行。
1. return的基础作用:返回结果 + 终止函数
|
def add(a, b): result = a + b return result # 返回结果,同时终止函数 print("这句代码不会执行!") # return后面的代码永远跑不到 |
接收返回值:用变量存起来,供后续使用
|
sum_result = add(3, 5) print(f"3+5的结果:{sum_result}") # 输出:3+5的结果:8 |
2. 函数可以返回多个值(用逗号分隔)
返回多个值时,Python 会自动把它们打包成 “元组”,接收时可以用多个变量 “解包”:
|
def calculate(a, b): sum_ab = a + b diff_ab = a - b product_ab = a * b # 积 quotient_ab = a / b # 商 return sum_ab, diff_ab, product_ab, quotient_ab # 返回4个值 |
接收多个返回值:
|
# 用4个变量接收(个数要和返回值一致) sum_r, diff_r, product_r, quotient_r = calculate(10, 2) print(f"和:{sum_r},差:{diff_r},积:{product_r},商:{quotient_r}") # 输出:和:12,差:8,积:20,商:5.0 # 用一个变量接收(会变成元组) result_tuple = calculate(10, 2) print(f"返回的元组:{result_tuple}") # 输出:返回的元组:(12, 8, 20, 5.0) |
3. 没有return的函数:默认返回None
如果函数里没写return,调用后会得到None(空值),常用于 “只做动作不返回结果” 的函数:
|
def print_hello(): print("Hello!") # 只有打印动作,没return # 调用函数,用变量接收返回值 result = print_hello() print(f"函数返回值:{result}") # 输出:Hello!,函数返回值:None |
五、函数嵌套:函数里套函数(复杂逻辑拆分)
就像 “洗衣机里有加水、洗衣、脱水的小模块”,函数里也能定义函数(嵌套函数),用来拆分复杂逻辑,让代码更清晰。
案例:计算 “两个数的平均值”,拆分成 “求和→求平均” 两个步骤
|
def calculate_average(a, b): """计算两个数的平均值(外层函数)""" # 定义嵌套函数:计算两数之和 def add_numbers(x, y): return x + y # 嵌套函数的返回值
# 调用嵌套函数(只能在outer函数里调用,外面用不了) total = add_numbers(a, b) # 计算平均值 average = total / 2 return average |
调用外层函数:
|
avg1 = calculate_average(10, 20) print(f"10和20的平均值:{avg1}") # 输出:10和20的平均值:15.0 avg2 = calculate_average(5, 15) print(f"5和15的平均值:{avg2}") # 输出:5和15的平均值:10.0 # 错误:嵌套函数不能在外面调用 # add_numbers(10, 20) # 报错:NameError: name 'add_numbers' is not defined |
六、新手易错点总结
- 函数调用在定义前面:
Python 从上到下执行,必须先写def 函数名(),再写函数名()调用,否则报错 “函数未定义”。
- 参数个数不匹配:
定义时写了 2 个参数,调用时只传 1 个,会报错missing 1 required positional argument;传多了会报错takes 2 positional arguments but 3 were given。
- 默认参数位置错误:
定义函数时,有默认值的参数必须放在没默认值的参数后面(比如def func(a, b=1)正确,def func(b=1, a)错误)。
- return 后面的代码不执行:
return不仅返回结果,还会终止函数,所以return后面的代码永远跑不到,别在后面写逻辑。
- 嵌套函数的作用域问题:
嵌套函数(内层函数)只能在 “定义它的外层函数” 里调用,外面调用会报错(作用域只在外部函数内)。
- *args和**kwargs的拆包问题:
传列表给*args时,要加*(比如func(*list));传字典给**kwargs时,要加**(比如func(**dict)),否则会把整个列表 / 字典当成一个参数。
七、练手小任务(动手巩固!)
- 任务 1:定义一个 “判断闰年” 的函数
规则:能被 4 整除但不能被 100 整除,或能被 400 整除的年份是闰年。
要求:函数接收 1 个参数(年份),返回True(是闰年)或False(不是闰年),并写说明文档。
- 任务 2:定义一个 “计算列表平均值” 的函数
要求:函数接收 1 个参数(列表,元素是数值),返回列表的平均值(总和 / 元素个数),如果列表为空,返回None并提示 “列表为空”。
- 任务 3:用*args定义一个 “找最大值” 的函数
要求:函数接收任意多个数值参数,返回其中的最大值(不用max()内置函数,自己用循环实现)。
- 任务 4:定义一个 “生成个人名片” 的函数(用**kwargs)
要求:函数接收任意多个关键字参数(比如name、job、company、phone),返回一个字符串名片,格式如下:
|
姓名:小明 职位:Python开发 公司:XX科技 电话:13812345678 |
下一篇我们会讲 “Python 基础语法 4:列表与字典”,详细讲解这两个最常用的 “数据容器”—— 列表用来存 “有序的多个数据”(比如购物清单),字典用来存 “键值对数据”(比如用户信息),它们和函数搭配使用,能实现更复杂的功能。如果练手时遇到问题,评论区留言,我会帮你分析解决!
更多推荐
所有评论(0)