科创科普:Python 函数——把重复代码装进「工具箱」

科创科普:Python 函数——把重复代码装进「工具箱」

一、什么时候该写函数 先看一段真实会出现的代码:程序要给三个同学的成绩算等级,于是「大于等于 90 是优秀,60 到 89 是及格,60 以下是待努力」这套判断被抄了三遍。三天后老师说要加一档「85 分以上为良好」,你就得在三个地方各改一次,漏掉一处就是 bug。 判断标准很简单:同一段逻辑写第二遍的时候,就该把它打包成一个函数。打包之后,这段逻辑只存在一份,改一次全部生效,调用处只剩一行名字,读代码的人一眼就知道它在干什么。 函数是编程里第一个真正的「抽象」工具:它让你从「一步步怎么做」升级到「调用一个能力」。

二、定义与调用:def、缩进、参数 定义函数的语法固定三步:关键字 def、函数名加括号、冒号,然后缩进写函数体。 def grade_of(score): if score >= 90: return "优秀" elif score >= 60: return "及格" else: return "待努力"

定义只是「造好了工具」,不会执行。要让工具干活必须调用: print(grade_of(95)) print(grade_of(58))

括号里的 score 叫参数,是函数的输入口;调用时传进去的 95 叫实参。参数可以有多个,用逗号隔开: def average(chinese, math, english): return (chinese + math + english) / 3

注意缩进:Python 用缩进划分「哪些行属于这个函数」,同一层必须对齐。少一个空格、多一个空格、或者用 Tab 和空格混着缩进,都会直接报 IndentationError。这是初学者遇到的第一个大坑,养成习惯:函数体统一用 4 个空格。

三、return 和 print 完全不是一回事 这是最容易混的一对概念,必须分清: · print 是把值显示在屏幕上给人看,看完就没了,程序拿不到这个值。 · return 是把值交回给调用者,可以被继续计算、存进变量、传给别的函数。 def bad_add(a, b): print(a + b)

def good_add(a, b): return a + b

x = bad_add(3, 5) # 屏幕上打印 8,但 x 的值是 None y = good_add(3, 5) # 屏幕上什么都不打印,y 的值是 8 print(y * 2) # 16

函数没有写 return 时,Python 自动返回 None。所以「打印出来了但变量是 None」几乎总是漏写了 return。 另一个细节:return 一旦执行,函数立刻结束,后面的语句不会再跑。把 return 写在循环里,就是「找到就提前收工」的写法: def first_negative(nums): for n in nums: if n < 0: return n return None

四、默认参数与关键字参数 有些参数大多数情况下取同一个值,可以给默认值: def area(width, height=1): return width * height

area(5) # 用默认 height=1,得 5 area(5, 3) # 传两个,得 15 area(height=3, width=5) # 用关键字传参,顺序可以打乱,得 15

两条硬规则: 1. 有默认值的参数必须放在没有默认值的参数后面。def f(a=1, b) 会直接语法报错。 2. 默认参数是在「定义时」就计算好的,不要在默认值里写列表或字典(例如 def add(item, box=[])),否则所有调用会共用同一个列表,越加越长。需要空列表时,用 box=None,在函数体里判断 if box is None: box = []。

五、作用域:函数里的变量「出门就失效」 函数内部赋值的变量叫局部变量,函数一结束它就消失了: def demo(): temp = 100 return temp

demo() print(temp) # NameError: temp 没有定义

这条规则的好处是隔离:你在函数里叫 score,不会意外改掉外面同名的 score。如果确实需要在函数内部修改外面的变量,要么用 global 声明(不建议,容易造成隐蔽 bug),要么更规范地「把值当参数传进去,把结果 return 出来」——这也是函数式写法的核心习惯:输入靠参数,输出靠返回值,不偷偷改外部状态。

六、案例:一个能复用的成绩统计工具 def load_scores(raw): return [float(x) for x in raw.split()]

def average(nums): if not nums: return 0.0 return sum(nums) / len(nums)

def grade_of(score): if score >= 90: return "优秀" elif score >= 85: return "良好" elif score >= 60: return "及格" return "待努力"

raw = "92 78 85 61 49" scores = load_scores(raw) avg = average(scores) print("平均分", round(avg, 1), "等级", grade_of(avg)) for s in scores: print(s, grade_of(s))

这段程序把「解析输入」「算平均」「判等级」拆成三个函数,每个只做一件事。以后要加「良好」这一档,只改 grade_of 一处;要把平均数换成中位数,只改 average,其他代码一行不动。这就是函数带来的可维护性——不是让代码变短,而是让改动有边界。

七、四个常见错误 · IndentationError:缩进不一致,或 Tab 与空格混用。 · NameError:函数里用了没定义的名字,常见于拼错参数名,或误以为函数内的变量在外面能用。 · TypeError:参数个数不对,比如 average() 需要 1 个参数却传了 0 个或 3 个。 · 返回 None:忘了写 return,或者把 return 写在 if 分支里导致某些情况走不到。 调试技巧:在函数第一行加一句 print("进入函数, 参数是", score),就能立刻看出函数到底有没有被调用、参数是什么。

八、练习 1. 写一个函数 is_even(n),返回 True 或 False,判断 n 是不是偶数。 2. 写一个函数 max_of3(a, b, c),不用 max(),返回三个数里最大的一个。 3. 下面这段代码输出什么?为什么? def f(x): x = x + 1 return x n = 5 f(n) print(n) 4. 写一个函数 count_vowels(s),统计字符串里 a、e、i、o、u 各出现多少次,返回一个字典。 5. 把「判断闰年」写成函数 leap(year),规则:能被 4 整除但不能被 100 整除,或者能被 400 整除。 6. 解释为什么 def add(item, box=[]) 是危险的,并给出正确写法。

参考答案思路 1. return n % 2 == 0。 2. 先假设 a 最大,再依次和 b、c 比较并更新,最后 return。 3. 输出 5。函数内部的 x = x + 1 只是让局部变量指向新值,不会改到外面的 n;想改外面的值,必须写成 n = f(n)。 4. 建一个字典 {'a':0,'e':0,...},遍历字符串,字符在字典里就 value 加一,最后 return。 5. return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0。 6. 默认值 [] 只在定义时创建一次,所有调用共用同一个列表,追加元素会互相污染。改成 def add(item, box=None): if box is None: box = []。