Python P5:函数——def、调用、参数、return,一次讲透
P3 的 for 循环、P4 的字典,都是"散装代码"——从上往下写一遍,干完就散。真实脚本里,同一段逻辑要在十个地方用:巡检 100 台服务器,总不能把 for 循环复制 100 遍。
函数就是把一段操作打包、起名、以后叫名字就能用。这是 Python 里最重要的组织方式,这篇一次讲透。
一、函数是什么:造一台机器
def double(number):
return number * 2
一句话:函数 = 封装好的一坨操作,起个名,以后叫名字就能用。
用"造机器"来理解,三个部分:
1. def double(number): —— 造机器,不干活
def= 定义(define),告诉 Python:我要造一台机器double= 机器的名字,你自己起,要见名知意(number)= 进料口,叫参数。现在里面什么都没有,是个空位冒号 + 缩进:老规矩
注意:def 这行只是把机器造好放那,一次都没运行。 屏幕上什么都不会发生。
2. 缩进里的代码 —— 机器内部的加工步骤
return number * 2
def 那行只给了名字和进料口,干什么活看缩进里的代码。这里的活就是:把传进来的 number 乘以 2。
3. 调用 —— 开机干活
result = double(3)
写出"函数名 + 括号"的那一刻,机器才开机。 double(3) 的意思是:叫 double 干活,原料是 3。
完整的时间顺序:
Python 先算等号右边:
double(3)开机,3 从进料口
number塞进去——这一瞬间number就是 3机器里算
number * 2,得到 6return 6把 6 递出来——这一刻,double(3)整个就变成了 6等号右边现在是 6,执行
result = 6
二、return:出货口
return 是机器内部的出货口,它的活有三件:
算:把后面的表达式算出来。
return number * 2,number 是 3 就算出 6递:把成品递到机器外面,交给调用的人
停:递完机器就停——
return后面的代码再也不执行
def check_disk(usage):
if usage > 90:
return "危险"
if usage > 70:
return "警告"
return "正常"
check_disk(95):第一个 if 命中,return "危险",直接出货停机,后面看都不看。
为什么不能写 result = return?
新手常问:return 在里面,result 在外面,干嘛不直接 result = return?
因为 return 是机器内部的出货口,只能写在 def 里面。你站在机器外面,够不着它。外面能用的只有函数名:
里面:
return负责往外递外面:
函数名(原料)负责叫它干活,result =负责接货
分工清楚,各管一头。
没有 return 的函数
def say_hello():
print("开机了!")
def say_hello(): 括号里没写参数——这台机器不要原料,调用时 say_hello() 也不用传。
它没有 return,只 print。这种函数干完活不交货,调用它的表达式的值是 None(P2 学过:空值)。print() 本身就是这种——打印完就完,不返回东西。
三、参数:进料口的规矩
位置对应
def add(first, second):
return first + second
add(2, 3) # first=2, second=3,按顺序对上
定义时留几个空位,调用时塞几个原料,按顺序一一对应。
原料可以是任何表达式
括号里放任何"能算出值"的东西都行,Python 先算出值再塞进去:
add(2, 3) # 具体的值
add(total, 3) # 变量(total 得先有值)
add(2 + 3, 10 - 1) # 算式,先算出 5 和 9 再传
add(len("abc"), 1) # 函数调用,先算出 3 再传
跟 f-string 的花括号一个规矩:括号里放表达式,先算出值再办事。
形参 vs 实参(名字别怕)
形参:
def里写的number、first,是空位的名字,只在机器内部有效实参:调用时塞的
3、total,是真正的东西
def double(number): # number 是形参,空位
return number * 2
n = 5
double(n) # n 是实参,传的是 5 这个值
里外都叫 number 也没关系——它们是两个世界的人,互不干扰。
四、调用:你早就一直在用
"调用"就是使用函数,写法固定:函数名 + 括号。
double(3)→ 调用了 double光写
double不加括号 → 不算调用,就是个名字
其实 P1 到现在,你一直在调用,只是没叫这个名字:
每个括号都是一次"开机"。方法就是"长在某个东西身上的函数":log.split() = 调用 log 身上的 split。
五、为什么需要函数:三个理由
1. 不复制粘贴
巡检 100 台服务器:
def check_server(name):
print(f"正在巡检 {name} ...")
# ... 一堆检查逻辑 ...
for server in ["web1", "web2", "db1"]:
check_server(server)
逻辑写一遍,调用 100 次。改逻辑只改一处。
2. 起名就是文档
parse_log(log) # 一看就知道:解析日志
check_disk(usage) # 检查磁盘
send_alert(message) # 发送告警
好名字顶半篇注释——这就是为什么变量名、函数名都要见名知意。
3. 分而治之
大任务拆成小函数,每个只干一件事:
def parse_log(log):
parts = log.split()
return {"date": parts[0], "time": parts[1], "level": parts[2]}
def is_error(info):
return info["level"] == "ERROR"
def format_alert(info, raw):
return f"[{info['time']}] 发现错误:{raw}"
for log in logs:
info = parse_log(log)
if is_error(info):
print(format_alert(info, log))
每个函数三五行,一眼看懂,合起来就是 P3 的日志巡检脚本——这就是"搭积木"式编程。
六、变量名规范(再强调一次)
函数名、变量名统一规矩:
只能用字母、数字、下划线,不能以数字开头
不能用关键字(
if、for、def、return…)区分大小写
小写 + 下划线,见名知意:
parse_log、error_count、server_ip
代码是写给人看的。名字起得好,三个月后回来看还一眼就懂。
小结
P1 到 P5,Python 的地基齐了:数据类型、字符串操作、流程控制、字典、函数。后面就是拿这些积木盖房子——文件读写、网络请求、浏览器自动化,番外篇见。