零基础怎么定义Python函数?参数传递与返回值基础教程
面向零基础读者的Python函数入门教程。通过图文解析与具体代码示例,详细讲解def定义语法、实参与形参传递、位置参数、关键字参数、默认参数以及return返回值处理,帮助你写出结构清晰、模块化的Python代码。
一、函数的基本定义与调用方式
在 Python 中,定义一个函数需要遵循严格的语法格式:首先使用关键字 def(define 的简写),空格后紧跟函数的名称,后面加上一对英文圆括号 (),括号内放置该函数需要接收的参数(如果不需要参数则留空),最后以英文冒号 : 结尾。从下一行开始,所有属于该函数的逻辑语句都必须向右缩进 4 个空格。
1. 定义一个最简单的无参数函数
下面是一个最基础的函数示例。它不需要外部传入任何参数,调用时直接在屏幕上打印提示信息:
def say_hello():
"""输出一条简单的欢迎语"""
print("你好,欢迎学习 Python 编程!")
# 函数调用:函数名加上英文圆括号
say_hello()
你好,欢迎学习 Python 编程!
定义函数本身只是“注册并打包”了一段逻辑,计算机此时并不会立刻运行函数体内的代码。只有当程序执行到 say_hello() 这行调用语句时,Python 解释器才会跳转进函数内部执行具体的打印操作。执行完毕后,控制权自动回到调用点下方继续向下推进。
2. 编写函数必须遵守的 3 条语法规矩
- 英文冒号不可遗漏:在
def 函数名():这一行的末尾,必须是英文冒号:。漏写冒号是初学者遇到SyntaxError: invalid syntax的首要原因。 - 严格的 4 空格缩进:Python 依靠缩进来判断代码行属于哪个作用域。函数体内部的代码必须统一向右缩进(推荐使用 4 个标准空格,不建议混用制表符 Tab)。
- 调用时必须带上圆括号:写
say_hello()表示“立即执行这个函数”;而如果只写say_hello,得到的是函数本身的对象引用,并不会真正触发执行。
二、参数传递:如何向函数输送数据?
现实中的任务大多依赖具体数据。例如计算折扣价格,函数必须先知道“原价是多少”和“折扣率是多少”。在函数定义的括号内声明的变量称为形参(形式参数),相当于预留好的数据插槽;而在调用函数时实际注入的数值则称为实参(实际参数)。
Python 提供了多种传参方式,常见且最核心的有三类:位置参数、关键字参数以及默认参数。
1. 位置参数(Positional Arguments)
位置参数是最自然的传参方式。调用时传入的值,按照从左向右的顺序,逐一绑定到对应的形参上。位置顺序一旦颠倒,计算逻辑就会出错。
def calculate_rectangle_area(width, height):
area = width * height
print(f"矩形宽度: {width}, 高度: {height}, 面积为: {area}")
# 按顺序依次对应:width=5, height=10
calculate_rectangle_area(5, 10)
矩形宽度: 5, 高度: 10, 面积为: 50
注意:如果定义了两个位置参数,调用时传了一个或者三个,Python 均会抛出 TypeError: calculate_rectangle_area() takes 2 positional arguments but ... were given。
2. 关键字参数(Keyword Arguments)
如果函数的参数较多,记住每个参数的位置次序往往容易犯错。此时可以在调用时通过 形参名 = 具体值 的语法明确指定对应关系。这种方式不受位置顺序的限制,并且代码可读性极高。
# 颠倒书写顺序依然精准对应
calculate_rectangle_area(height=12, width=4)
在同一次函数调用中,如果同时混用位置参数和关键字参数,所有的位置实参必须严格排在所有关键字实参的左边。例如 calculate_rectangle_area(4, height=12) 是合法的,但 calculate_rectangle_area(height=12, 4) 会直接产生语法错误。
3. 默认参数(Default Arguments)
如果某个参数在绝大多数情况下都是一个固定值,可以在定义函数时直接为该形参赋值。调用者如果不传这个参数,函数自动使用预设的默认值;调用者如果传入了新值,则会覆盖默认值。
def generate_greeting(user_name, action="登录成功"):
print(f"系统提示:用户 [{user_name}] 已经{action}。")
# 场景一:采用默认参数,省略第二个实参
generate_greeting("Alice")
# 场景二:主动传入新实参,覆盖默认值
generate_greeting("Bob", "修改了密码")
系统提示:用户 [Alice] 已经登录成功。
系统提示:用户 [Bob] 已经修改了密码。
Python 中的默认参数是在定义函数的那一刻被计算并初始化的,而不是每次调用时重新创建。如果你写了 def collect_data(item, box=[]):,那么每次不传 box 的调用都会共享同一个列表对象,导致多次调用的数据不断累积污染。
官方推荐标准写法:将默认值设置为 None,并在函数内部通过判断来新建对象:
def collect_data(item, box=None):
if box is None:
box = [] # 每次进入函数动态创建全新的独立列表
box.append(item)
return box
三、返回值详解:函数如何把结果交回调用方?
在前面的例子中,我们在函数内部使用了 print(),但 print() 仅仅是把文字打在终端控制台上,外部代码根本拿不到这个计算结果。要让函数产出的数据能够参与外部后续的计算、写入文件或存入数据库,必须使用 return 语句。
1. return 的两大核心作用
- 向外交付数据:把
return后面紧跟的表达式结果交还给函数的调用者。外部可以通过赋值变量(如result = my_func())来接收这个值。 - 立即终止执行:一旦程序运行到
return,函数会立刻退出,该语句之后的任何代码(死代码)都不会再被执行。
def apply_discount(original_price, discount_rate=0.1):
"""计算折后价格并返回最终数值"""
if original_price < 0:
return 0.0 # 拦截异常输入并提前退出
discounted = original_price * (1 - discount_rate)
return discounted # 交付运算结果
# 接收返回值并进行二次运算
pay_amount = apply_discount(200, 0.2)
final_bill = pay_amount + 10 # 加上10元运费
print(f"最终账单金额: {final_bill} 元")
最终账单金额: 170.0 元
2. 没有写 return 会怎样?
如果一个函数执行完毕时没有遇到 return,或者只写了单个关键字 return 而没跟任何值,Python 会在幕后默认返回一个特殊对象:None。例如:
def log_message(msg):
print(f"[日志] {msg}")
res = log_message("系统已启动")
print("res 的值是:", res)
[日志] 系统已启动
res 的值是: None
3. 返回多个值:元组打包与解包
在很多实际业务中,我们希望函数一次性输出多个处理结果,例如“商品折后价”与“共计节省的金额”。在 Python 中,只需在 return 后面用英文逗号分隔多个变量。Python 会自动将它们打包为一个元组(Tuple)返回;而在调用方,可以用等量的变量直接进行优雅的解包接收:
def calculate_order_summary(price, discount=0.15):
saved = price * discount
pay = price - saved
return pay, saved # 实际上返回了一个元组 (pay, saved)
# 一次性用两个变量接收返回结果(解包)
actual_pay, total_saved = calculate_order_summary(500, 0.2)
print(f"实付: {actual_pay} 元,立省: {total_saved} 元")
实付: 400.0 元,立省: 100.0 元
四、综合演练与新手避坑决策指南
为了将上述知识融会贯通,我们通过一个完整的电商结账模块进行演练。该函数综合运用了位置参数(商品单价)、默认参数(购买数量、满减券面额)、边界防御检查以及多返回值机制:
def checkout(unit_price, quantity=1, coupon=0):
"""
结账金额计算函数
:param unit_price: 商品单价(必需)
:param quantity: 购买数量(默认为1)
:param coupon: 优惠券抵扣面额(默认为0)
:return: (最终实付金额, 是否享受优惠标志)
"""
if unit_price <= 0 or quantity <= 0:
return 0.0, False # 校验无效输入
subtotal = unit_price * quantity
final_amount = max(0.0, subtotal - coupon)
has_discount = coupon > 0
return final_amount, has_discount
# 测试调用一:纯默认值购买1件
pay1, is_disc1 = checkout(89.9)
print(f"单件购买支付: {pay1} 元, 优惠状态: {is_disc1}")
# 测试调用二:批量购买3件并使用20元优惠券
pay2, is_disc2 = checkout(120.0, quantity=3, coupon=20)
print(f"多件抵扣支付: {pay2} 元, 优惠状态: {is_disc2}")
单件购买支付: 89.9 元, 优惠状态: False
多件抵扣支付: 340.0 元, 优惠状态: True
初学者高频报错对照表
| 常见报错或表现 | 常见诱发根因 | 修正建议与应对方式 |
|---|---|---|
SyntaxError: invalid syntax |
def 声明语句末尾漏写了英文冒号 : |
检查行末,补全英文冒号。 |
IndentationError: expected an indented block |
函数内部主体没有缩进,或者缩进空格数不一致 | 统一使用 4 个半角空格进行层级缩进。 |
SyntaxError: non-default argument follows default argument |
把带有默认值的形参写在了无默认值形参的左边 | 调整形参顺序:所有默认参数一律排在右侧。 |
TypeError: unsupported operand type for ... 'NoneType' |
本该返回数字的函数里漏写了 return,误用了 print() |
在函数末尾显式使用 return 运算结果 交付数据。 |
打印结果出现 <function my_func at 0x...> |
调用函数时漏写了末尾的英文圆括号 () |
执行函数必须带括号:my_func()。 |
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









