第12章 函数
引言
想象一下,你在玩一个电子游戏。游戏中有一些特殊的动作,比如“跳跃“、“攻击”、“防守”。每次你需要做这些动作时,只需要按一个对应的按钮,游戏角色就会执行这个动作。你不需要每次都重新告诉电脑“抬起左腿、向前移动、放下左腿…“——所有这些复杂的步骤都已经被打包到“跳跃“这个按钮里了。
在Python中,也有这样一种机制,让我们可以把一段代码打包起来,给它起个名字,以后就可以通过这个名字重复使用这段代码。这就是函数(Function)。
你已经学过的函数!
其实,你早就在数学课上见过“函数“了!还记得数学里的函数吗?
比如,有一个数学函数:
f(x) = 2x + 1
当我们把x = 3代入这个函数时:
f(3) = 2 × 3 + 1 = 7
当我们把x = 5代入时:
f(5) = 2 × 5 + 1 = 11
你看,数学函数就是这么一个“规则“或“公式“,你给它一个输入值(x),它就按照固定的规则计算,给你一个输出值(结果)。
Python函数和数学函数非常相似!
- 数学函数:接收一个数,按公式计算,返回结果
- Python函数:接收一些数据,执行代码,返回结果
它们都有:
- 一个名字(比如f、g、draw_square)
- 输入(参数)
- 处理过程(计算或代码)
- 输出(返回值)
给家长的小贴士:
- 如果孩子已经学过数学函数,可以用数学函数作为类比,这样孩子会更容易理解Python函数的概念
- 如果孩子还没学过数学函数,可以用“遥控器按钮“、“快捷指令”、“预设程序“等生活中的例子来类比函数
- 重点强调“输入→处理→输出“这个模式,这是所有函数的核心特征
为什么需要函数
问题:重复的代码
在学习循环语句时,我们用turtle画过很多图形。现在让我们画一个正方形:
import turtle
t = turtle.Pen()
# 画一个正方形
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
turtle.done()
运行这段代码,会在屏幕上画出一个边长为100的正方形。
现在,如果我们要画两个正方形呢?
import turtle
t = turtle.Pen()
# 画第一个正方形
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
# 移动到新位置
t.penup()
t.goto(150, 0)
t.pendown()
# 画第二个正方形
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
turtle.done()
你注意到什么问题了吗?画正方形的代码重复了两次!如果我们要画10个正方形,难道要复制粘贴10次吗?
解决方案:使用函数
函数可以帮我们解决这个问题。我们可以把“画正方形“的代码打包成一个函数:
import turtle
t = turtle.Pen()
# 定义一个画正方形的函数
def draw_square():
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
# 使用函数画第一个正方形
draw_square()
# 移动到新位置
t.penup()
t.goto(150, 0)
t.pendown()
# 使用函数画第二个正方形
draw_square()
turtle.done()
现在代码变得简洁多了!我们只需要调用draw_square()函数,就可以画出一个正方形。
给家长的小贴士:强调函数的两个主要好处:1)避免重复代码;2)让代码更易读、易维护。可以告诉孩子,如果以后想修改正方形的画法,只需要修改函数定义,而不需要修改每一处调用的地方。
函数的基本概念
什么是函数
函数是一个可以重复使用的代码块,它有一个名字,当我们需要使用这段代码时,只需要调用这个名字。
数学函数 vs Python函数
让我们对比一下数学函数和Python函数:
数学函数示例:
f(x) = x² (平方函数)
g(x, y) = x + y (加法函数)
对应的Python函数:
def f(x):
return x * x
def g(x, y):
return x + y
你看,它们的结构几乎一样!
| 数学函数 | Python函数 | 说明 |
|---|---|---|
| f(x) = x² | def f(x): return x * x | 函数名是f,参数是x |
| g(a, b) = a + b | def g(a, b): return a + b | 函数名是g,有两个参数a和b |
| y = f(3) | y = f(3) | 调用函数,传入参数3 |
定义函数的语法
def 函数名(参数1, 参数2, ...):
函数体(要执行的代码)
return 返回值
让我们分解这个语法:
def:这是Python的关键字,告诉计算机“我要定义一个函数了“(就像数学课上说“设f(x) = …“一样)函数名:给函数起的名字,命名规则和变量名一样(数学里常用f、g、h,Python里常用有意义的名字)(参数1, 参数2, ...):圆括号,里面可以放参数(就像数学函数f(x)中的x)::冒号,表示函数定义的开始函数体:缩进的代码块,是函数要执行的内容(就像数学公式中的计算规则)return:返回计算结果(就像数学函数计算出结果)
从数学函数到Python函数
让我们把一些常见的数学函数转换成Python代码:
示例1:绝对值函数
数学中的绝对值函数:
f(x) = |x|
Python实现:
def absolute_value(x):
"""计算x的绝对值(对应数学函数 f(x) = |x|)"""
if x >= 0:
return x
else:
return -x
# 测试
print(absolute_value(5)) # 输出: 5
print(absolute_value(-5)) # 输出: 5
print(absolute_value(0)) # 输出: 0
示例2:简单线性函数
数学函数:
f(x) = 2x + 3
Python实现:
def linear_function(x):
"""计算2x + 3(线性函数)"""
return 2 * x + 3
# 测试
print(linear_function(1)) # 输出: 5 (2×1+3=5)
print(linear_function(5)) # 输出: 13 (2×5+3=13)
print(linear_function(0)) # 输出: 3 (2×0+3=3)
给家长的数学提示:
- 绝对值函数| x |是小学高年级数学的内容,表示一个数到0的距离
- 线性函数 f(x) = ax + b 的形式也很适合作为入门例子
- 可以鼓励孩子用Python验证他们学过的数学计算
一个简单的例子
# 定义一个打招呼的函数
def say_hello():
print("你好!")
print("欢迎来到Python世界!")
print("让我们一起学习编程吧!")
# 调用函数
say_hello()
print("-----分隔线-----")
# 再次调用函数
say_hello()
输出:
你好!
欢迎来到Python世界!
让我们一起学习编程吧!
-----分隔线-----
你好!
欢迎来到Python世界!
让我们一起学习编程吧!
给家长的小贴士:解释函数的“定义“和“调用“是两个不同的步骤。定义函数就像是在编写一本“操作手册“或数学公式,而调用函数就像是按照手册执行操作或代入数值计算。定义函数时,代码不会立即执行,只有调用时才会执行。
函数的参数
问题:函数太死板
现在我们有了一个画正方形的函数:
import turtle
t = turtle.Pen()
def draw_square():
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
# 在不同位置画正方形
draw_square()
t.penup()
t.goto(150, 0)
t.pendown()
draw_square()
turtle.done()
这个函数有一个问题:它只能画边长为100的正方形。如果我们想画不同大小的正方形怎么办?
解决方案:带参数的函数
我们可以给函数添加参数,让函数更灵活:
import turtle
t = turtle.Pen()
def draw_square(size):
t.forward(size)
t.left(90)
t.forward(size)
t.left(90)
t.forward(size)
t.left(90)
t.forward(size)
t.left(90)
# 画一个边长为50的正方形
draw_square(50)
# 移动位置
t.penup()
t.goto(100, 0)
t.pendown()
# 画一个边长为100的正方形
draw_square(100)
# 移动位置
t.penup()
t.goto(250, 0)
t.pendown()
# 画一个边长为150的正方形
draw_square(150)
turtle.done()
现在draw_square()函数可以根据传入的参数画出不同大小的正方形了!
什么是参数
参数就像是函数的“输入“,让我们可以向函数传递信息。
数学函数的参数:
f(x) = 2x + 1
↑
参数(自变量)
当我们说f(5)时,5就是传入参数的值。
Python函数的参数:
def double(x): # x是参数(形参)
return 2 * x
result = double(5) # 5是实参
- 参数(Parameter/形参):函数定义时括号里的变量名(就像数学函数中的x)
- 实参(Argument):调用函数时传入的实际值(就像代入x的具体数值)
def draw_square(size): # size是参数(形参)
t.forward(size)
t.left(90)
...
draw_square(100) # 100是实参
数学练习:理解参数
让我们通过数学练习来理解参数的概念:
练习1:理解函数调用
数学函数: f(x) = x²
如果我们计算:
- f(2) = 4
- f(5) = 25
- f(10) = 100
这里2、5、10都是“实参“,x是“参数“(形参)
对应的Python代码:
def square(x): # x是参数
return x * x
print(square(2)) # 输出: 4
print(square(5)) # 输出: 25
print(square(10)) # 输出: 100
练习2:多参数函数
数学函数: f(x, y) = x + y
计算:
- f(3, 5) = 8
- f(10, 20) = 30
对应的Python代码:
def add(x, y):
return x + y
print(add(3, 5)) # 输出: 8
print(add(10, 20)) # 输出: 30
多个参数
函数可以有多个参数,用逗号分隔:
import turtle
t = turtle.Pen()
def draw_rectangle(width, height):
"""画一个矩形"""
t.forward(width)
t.left(90)
t.forward(height)
t.left(90)
t.forward(width)
t.left(90)
t.forward(height)
t.left(90)
# 画不同大小的矩形
draw_rectangle(100, 50)
t.penup()
t.goto(150, 0)
t.pendown()
draw_rectangle(50, 100)
turtle.done()
位置参数
当我们调用函数时,实参会按照位置对应到参数:
def greet(name, age):
print(f"你好,我叫{name},今年{age}岁")
# 第一个值对应name,第二个值对应age
greet("小明", 12) # 输出: 你好,我叫小明,今年12岁
# 如果顺序错了,结果也会错
greet(12, "小明") # 输出: 你好,我叫12,今年小明岁(错了!)
给家长的小贴士:可以用“快递包裹“来类比参数。快递单上有“寄件人“、“收件人”、“地址“等字段(参数),填写快递单时需要把具体信息(实参)填入对应的字段。
练习:为函数添加颜色参数
我们可以让画正方形的函数支持颜色选择:
import turtle
t = turtle.Pen()
def draw_colored_square(size, color):
"""画一个指定大小和颜色的正方形"""
t.color(color) # 设置颜色
t.begin_fill() # 开始填充
t.forward(size)
t.left(90)
t.forward(size)
t.left(90)
t.forward(size)
t.left(90)
t.forward(size)
t.left(90)
t.end_fill() # 结束填充
# 画不同颜色的正方形
draw_colored_square(100, "red")
t.penup()
t.goto(120, 0)
t.pendown()
draw_colored_square(100, "blue")
t.penup()
t.goto(240, 0)
t.pendown()
draw_colored_square(100, "green")
turtle.done()
练习:画一排正方形
结合循环,我们可以画一排正方形:
import turtle
t = turtle.Pen()
t.speed(0) # 设置最快速度
def draw_square(size, color):
"""画一个正方形"""
t.color(color)
t.begin_fill()
for i in range(4):
t.forward(size)
t.left(90)
t.end_fill()
# 画一排正方形
colors = ["red", "orange", "yellow", "green", "blue"]
for i in range(5):
draw_square(50, colors[i])
t.penup()
t.forward(70)
t.pendown()
turtle.done()
默认参数
什么需要默认参数
有时候,我们希望函数的某些参数有默认值。这样,调用函数时如果不提供这个参数,就会使用默认值。
import turtle
t = turtle.Pen()
def draw_square(size, color="red"):
"""画正方形,默认颜色是红色"""
t.color(color)
t.begin_fill()
for i in range(4):
t.forward(size)
t.left(90)
t.end_fill()
# 不指定颜色,使用默认的红色
draw_square(100)
t.penup()
t.goto(120, 0)
t.pendown()
# 指定颜色为蓝色
draw_square(100, "blue")
turtle.done()
默认参数的规则
- 默认参数必须在非默认参数之后
- 调用函数时,可以只给部分参数赋值
# 错误的例子
def draw_square(color="red", size): # 错误!默认参数在后面
...
# 正确的例子
def draw_square(size, color="red"): # 正确!
...
# 调用时可以只给第一个参数
draw_square(100) # color使用默认值"red"
给家长的小贴士:可以用“订购商品“来类比默认参数。比如订购pizza时,默认配料是芝士,但你可以选择添加其他配料。
函数的返回值
什么是返回值
数学函数的返回值:
f(x) = x²
f(3) = 9 ← 9就是返回值(因变量)
在数学中,我们把函数计算的结果叫做“函数值“或“因变量“。
Python函数的返回值:
到目前为止,我们的函数都是执行某些操作(画图、打印等)。但有时,我们希望函数能够“返回“一个结果,让我们可以在程序中使用这个结果。这就像数学函数计算出一个数值一样。
# 计算矩形的面积(对应数学函数 A = w × h)
def calculate_area(width, height):
area = width * height
return area # 返回计算结果,就像数学函数得出答案
# 调用函数并获取返回值
result = calculate_area(10, 5)
print(f"矩形的面积是: {result}")
return语句:数学函数的“=“号
在数学函数中,我们用“=“号表示结果:
f(x) = 2x + 1
f(3) = 7 ← 计算结果是7
在Python中,我们用return语句返回结果:
def f(x):
return 2 * x + 1 # 返回计算结果
result = f(3) # result的值是7
可以把return理解为数学中的“等于“——它告诉Python:“这个函数的值是xxx”。
从数学公式到Python函数
让我们把一些常见的数学公式转换成Python函数:
示例1:矩形面积公式
数学公式: A = 长 × 宽
def rectangle_area(length, width):
"""计算矩形面积 A = l × w"""
return length * width
# 测试
print(rectangle_area(10, 5)) # 输出: 50
print(rectangle_area(8, 3)) # 输出: 24
示例2:矩形周长公式
数学公式: P = 2 × (长 + 宽)
def rectangle_perimeter(length, width):
"""计算矩形周长 P = 2(l + w)"""
return 2 * (length + width)
# 测试
print(rectangle_perimeter(10, 5)) # 输出: 30
print(rectangle_perimeter(8, 3)) # 输出: 22
示例3:三角形面积公式(海伦公式)
数学公式: A = √[s(s-a)(s-b)(s-c)] 其中 s = (a+b+c)/2
import math
def triangle_area(a, b, c):
"""用海伦公式计算三角形面积"""
s = (a + b + c) / 2 # 半周长
area = math.sqrt(s * (s - a) * (s - b) * (s - c))
return area
# 测试:边长为3, 4, 5的三角形(直角三角形)
print(triangle_area(3, 4, 5)) # 输出: 6.0 (应该是6,因为3×4÷2=6)
示例4:圆的面积和周长
数学公式:
- 面积: A = πr²
- 周长: C = 2πr
import math
def circle_area(radius):
"""计算圆的面积 A = πr²"""
return math.pi * radius * radius
def circle_circumference(radius):
"""计算圆的周长 C = 2πr"""
return 2 * math.pi * radius
# 测试:半径为5的圆
r = 5
print(f"半径为{r}的圆:")
print(f" 面积: {circle_area(r):.2f}")
print(f" 周长: {circle_circumference(r):.2f}")
给家长的数学提示:
- 这些公式都是小学高年级或初中数学的内容
- 可以让孩子先用数学方法手工计算,再用Python验证
- 海伦公式可能比较难,可以根据孩子的情况决定是否讲解
- 圆周率π用
math.pi表示,这是Python数学库提供的精确值
返回值的使用
返回值可以像普通变量一样使用:
def calculate_rectangle_area(width, height):
return width * height
def calculate_circle_area(radius):
return 3.14 * radius * radius
# 比较两个面积
rectangle = calculate_rectangle_area(10, 5)
circle = calculate_circle_area(5)
print(f"矩形面积: {rectangle}")
print(f"圆形面积: {circle:.2f}")
if rectangle > circle:
print("矩形的面积更大")
else:
print("圆形的面积更大")
多个返回值
函数可以返回多个值:
def calculate(width, height):
"""计算矩形的面积和周长"""
area = width * height
perimeter = 2 * (width + height)
return area, perimeter
# 接收多个返回值
a, p = calculate(10, 5)
print(f"面积: {a}, 周长: {p}")
给家长的小贴士:可以用“自动售货机“来类比返回值。你投入硬币(参数),按下按钮(调用函数),机器会“返回“商品(返回值)。
练习:温度转换函数
def celsius_to_fahrenheit(celsius):
"""将摄氏度转换为华氏度"""
fahrenheit = celsius * 9/5 + 32
return fahrenheit
def fahrenheit_to_celsius(fahrenheit):
"""将华氏度转换为摄氏度"""
celsius = (fahrenheit - 32) * 5/9
return celsius
# 测试函数
temp_c = 25
temp_f = celsius_to_fahrenheit(temp_c)
print(f"{temp_c}°C = {temp_f}°F")
temp_f = 77
temp_c = fahrenheit_to_celsius(temp_f)
print(f"{temp_f}°F = {temp_c:.1f}°C")
变量的作用域
局部变量
在函数内部定义的变量叫做局部变量,它们只能在函数内部使用:
def my_function():
local_var = 10 # 局部变量
print(f"函数内部: local_var = {local_var}")
my_function() # 输出: 函数内部: local_var = 10
# 下面这行会报错!
# print(local_var) # NameError: name 'local_var' is not defined
全局变量
在函数外部定义的变量叫做全局变量,它们可以在整个程序中使用:
global_var = 100 # 全局变量
def my_function():
print(f"函数内部可以访问: global_var = {global_var}")
my_function() # 输出: 函数内部可以访问: global_var = 100
print(f"函数外部也可以访问: global_var = {global_var}")
全局变量和局部变量的同名
如果全局变量和局部变量同名,局部变量会“遮蔽“全局变量:
x = 10 # 全局变量
def my_function():
x = 20 # 局部变量,不影响全局变量
print(f"函数内部: x = {x}")
my_function() # 输出: 函数内部: x = 20
print(f"函数外部: x = {x}") # 输出: 函数外部: x = 10
在函数中修改全局变量
如果想在函数中修改全局变量,需要使用global关键字:
x = 10 # 全局变量
def modify_global():
global x # 声明要使用全局变量x
x = 20
print(f"函数内部修改后: x = {x}")
print(f"修改前: x = {x}") # 输出: 修改前: x = 10
modify_global() # 输出: 函数内部修改后: x = 20
print(f"修改后: x = {x}") # 输出: 修改后: x = 20
给家长的小贴士:作用域是一个比较抽象的概念。可以用“家里的房间“来类比:每个房间(函数)都有自己的私人物品(局部变量),但客厅(全局区域)的物品大家都可以用。
函数的文档字符串
什么是文档字符串
文档字符串(Docstring)是用来说明函数功能的注释,放在函数定义的第一行:
def calculate_area(width, height):
"""
计算矩形的面积
参数:
width: 矩形的宽度
height: 矩形的高度
返回:
矩形的面积
"""
return width * height
查看文档字符串
可以使用help()函数查看文档字符串:
def greet(name):
"""向指定的人打招呼"""
print(f"你好, {name}!")
# 查看文档字符串
help(greet)
输出:
Help on function greet in module __main__:
greet(name)
向指定的人打招呼
给家长的小贴士:教导孩子养成写文档字符串的好习惯,这就像给函数写“使用说明书“,以后自己或别人使用这个函数时,就能快速了解它的功能。
函数的高级应用
画花朵图案
让我们用函数画一个美丽的花朵图案:
import turtle
t = turtle.Pen()
t.speed(0)
def draw_petal(size, angle):
"""画一个花瓣"""
for i in range(2):
t.circle(size, angle)
t.left(180 - angle)
def draw_flower(x, y, size, petal_count, color):
"""在指定位置画一朵花"""
t.penup()
t.goto(x, y)
t.pendown()
t.color(color)
t.begin_fill()
# 画花瓣
for i in range(petal_count):
draw_petal(size, 60)
t.left(360 / petal_count)
t.end_fill()
# 画不同的花朵
draw_flower(-100, 100, 50, 6, "red")
draw_flower(100, 100, 40, 8, "yellow")
draw_flower(0, -100, 60, 10, "purple")
turtle.done()
画N角星
编写一个函数,可以画任意角数的星:
import turtle
t = turtle.Pen()
t.speed(0)
def draw_star(x, y, size, points, color, angle=None):
"""
画一个N角星
参数:
x, y: 位置
size: 大小
points: 角的数量
color: 颜色
angle: 旋转角度(可选)
"""
t.penup()
t.goto(x, y)
t.pendown()
if angle is not None:
t.right(angle)
t.color(color)
t.begin_fill()
# 计算角度
if points == 5:
exterior_angle = 144
else:
exterior_angle = 180 - 180 / points
for i in range(points):
t.forward(size)
t.right(exterior_angle)
t.end_fill()
# 画不同的星星
draw_star(-100, 100, 100, 5, "yellow", 0) # 五角星
draw_star(100, 100, 80, 6, "red", 30) # 六角星
draw_star(0, -100, 120, 8, "blue", 45) # 八角星
turtle.done()
递归函数
什么是递归
递归是指函数调用自身。听起来很奇怪,但这是一个非常强大的编程技巧。
递归就像数学归纳法
如果你学过数学归纳法,递归的概念就很相似了:
数学归纳法证明:
- 基准情况:证明当n=1时命题成立
- 归纳假设:假设当n=k时命题成立
- 归纳递推:证明当n=k+1时命题也成立
递归函数:
- 基准情况:最简单的情况,直接返回结果
- 递归调用:调用自身解决更小的问题
- 递归推进:每次调用要朝着基准情况前进
递归的要素
编写递归函数时,必须注意以下几点:
- 必须有退出条件(基准情况)
- 每次调用时,参数要发生变化
- 参数变化要朝着退出条件的方向进行
递归示例1:阶乘
数学定义:
n! = n × (n-1) × (n-2) × ... × 2 × 1
递归定义:
n! = n × (n-1)! (当n > 1时)
1! = 1 (基准情况)
比如:
- 5! = 5 × 4!
- 4! = 4 × 3!
- 3! = 3 × 2!
- 2! = 2 × 1!
- 1! = 1 (基准情况)
Python实现:
def factorial(n):
"""计算n的阶乘 n!"""
# 退出条件(基准情况)
if n == 1:
return 1
# 递归调用
return n * factorial(n - 1)
# 测试
print(factorial(5)) # 输出: 120
print(factorial(4)) # 输出: 24
print(factorial(1)) # 输出: 1
让我们追踪一下factorial(5)的执行过程:
factorial(5)
= 5 * factorial(4)
= 5 * (4 * factorial(3))
= 5 * (4 * (3 * factorial(2)))
= 5 * (4 * (3 * (2 * factorial(1))))
= 5 * (4 * (3 * (2 * 1))) ← 到达基准情况!
= 5 * (4 * (3 * 2))
= 5 * (4 * 6)
= 5 * 24
= 120
递归示例2:求和
数学定义: 计算1到n的和:
S(n) = 1 + 2 + 3 + ... + n
递归定义:
S(n) = n + S(n-1) (当n > 1时)
S(1) = 1 (基准情况)
Python实现:
def sum_to_n(n):
"""递归计算1到n的和"""
# 退出条件
if n == 1:
return 1
# 递归调用
return n + sum_to_n(n - 1)
# 测试
print(sum_to_n(5)) # 输出: 15 (1+2+3+4+5)
print(sum_to_n(10)) # 输出: 55
数学验证: 可以用等差数列求和公式验证:
S(n) = n(n+1)/2
S(10) = 10×11/2 = 55 ✓
Python验证:
def sum_formula(n):
"""用公式计算1到n的和: S = n(n+1)/2"""
return n * (n + 1) // 2
print(sum_formula(10)) # 输出: 55
递归示例3:斐波那契数列
数学背景:
斐波那契数列是一个著名的数学数列,它在自然界中随处可见(比如花朵的花瓣数、蜗牛的壳纹等)。
数列是这样的:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...
递归定义:
F(n) = F(n-1) + F(n-2) (当n > 2时)
F(1) = 1 (基准情况)
F(2) = 1 (基准情况)
规律是:每个数都是前两个数之和。
比如:
- F(3) = F(2) + F(1) = 1 + 1 = 2
- F(4) = F(3) + F(2) = 2 + 1 = 3
- F(5) = F(4) + F(3) = 3 + 2 = 5
Python实现:
def fibonacci(n):
"""计算斐波那契数列的第n项"""
# 退出条件
if n == 1 or n == 2:
return 1
# 递归调用
return fibonacci(n - 1) + fibonacci(n - 2)
# 打印前10项
for i in range(1, 11):
print(fibonacci(i), end=" ")
# 输出: 1 1 2 3 5 8 13 21 34 55
数学小知识:
- 斐波那契数列的相邻两项比值会越来越接近“黄金比例“φ ≈ 1.618
- F(n+1)/F(n) ≈ 1.618 (当n很大时)
让我们验证一下:
def fibonacci(n):
if n == 1 or n == 2:
return 1
return fibonacci(n - 1) + fibonacci(n - 2)
# 计算比值
for i in range(5, 16):
ratio = fibonacci(i + 1) / fibonacci(i)
print(f"F({i+1})/F({i}) = {ratio:.6f}")
递归示例:画分形树
import turtle
t = turtle.Pen()
t.speed(0)
t.left(90)
def draw_tree(branch_length, pen_size):
"""画分形树"""
if branch_length < 10:
return
# 设置画笔粗细
t.pensize(pen_size)
# 画树干
t.forward(branch_length)
# 画右边的树枝
t.right(20)
draw_tree(branch_length * 0.7, pen_size * 0.7)
# 画左边的树枝
t.left(40)
draw_tree(branch_length * 0.7, pen_size * 0.7)
# 回到树干
t.right(20)
t.penup()
t.backward(branch_length)
t.pendown()
# 画树
draw_tree(100, 10)
turtle.done()
给家长的小贴士:递归是一个比较难理解的概念。可以用“俄罗斯套娃“或“照镜子“来类比。提醒孩子,递归必须有退出条件,否则会陷入无限循环(就像程序里跑进了一个永远出不去的迷宫)。如果孩子学过数学归纳法,可以用数学归纳法来类比递归的思想。
数学函数练习
让我们通过一些数学练习来巩固函数的概念!
练习1:最大值函数
编写一个函数,找出两个数中的最大值。
数学定义:
max(a, b) = a (如果 a ≥ b)
max(a, b) = b (如果 a < b)
查看答案
def maximum(a, b):
"""返回两个数中的最大值"""
if a >= b:
return a
else:
return b
# 测试
print(maximum(5, 3)) # 输出: 5
print(maximum(2, 8)) # 输出: 8
print(maximum(4, 4)) # 输出: 4
练习2:最小公倍数(LCM)
编写一个函数,计算两个数的最小公倍数。
数学背景: 最小公倍数是能够被这两个数整除的最小的正整数。
比如:
- LCM(4, 6) = 12 (12能被4和6整除)
- LCM(3, 5) = 15 (15能被3和5整除)
公式:
LCM(a, b) = (a × b) / GCD(a, b)
其中GCD是最大公约数。
查看答案
def gcd(a, b):
"""计算最大公约数(欧几里得算法)"""
while b != 0:
a, b = b, a % b
return a
def lcm(a, b):
"""计算最小公倍数"""
return (a * b) // gcd(a, b)
# 测试
print(f"LCM(4, 6) = {lcm(4, 6)}") # 输出: 12
print(f"LCM(3, 5) = {lcm(3, 5)}") # 输出: 15
print(f"LCM(12, 18) = {lcm(12, 18)}") # 输出: 36
练习3:判断素数
编写一个函数,判断一个数是否为素数。
数学背景: 素数是只能被1和它本身整除的大于1的正整数。
比如:2, 3, 5, 7, 11, 13, 17, 19, …
查看答案
def is_prime(n):
"""判断n是否为素数"""
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
# 只需要检查到√n
i = 3
while i * i <= n:
if n % i == 0:
return False
i += 2
return True
# 测试
for i in range(1, 21):
if is_prime(i):
print(i, end=" ")
# 输出: 2 3 5 7 11 13 17 19
给家长的数学提示:
- 最大公约数可以用欧几里得算法计算,这是一个经典的算法
- 判断素数时,只需要检查到√n,因为如果n有因数,必然有一个≤√n
- 这些练习可以帮孩子复习数学概念,同时学习Python编程
练习4:摄氏度和华氏度转换
编写两个函数,实现温度单位转换。
数学公式:
- 摄氏度转华氏度: F = C × 9/5 + 32
- 华氏度转摄氏度: C = (F - 32) × 5/9
查看答案
def celsius_to_fahrenheit(c):
"""摄氏度转华氏度: F = C × 9/5 + 32"""
return c * 9/5 + 32
def fahrenheit_to_celsius(f):
"""华氏度转摄氏度: C = (F - 32) × 5/9"""
return (f - 32) * 5/9
# 测试
print(f"25°C = {celsius_to_fahrenheit(25):.1f}°F") # 输出: 77.0°F
print(f"77°F = {fahrenheit_to_celsius(77):.1f}°C") # 输出: 25.0°C
# 常见温度对比
print(f"\n水的冰点: 0°C = {celsius_to_fahrenheit(0)}°F")
print(f"水的沸点: 100°C = {celsius_to_fahrenheit(100)}°F")
print(f"人体体温: 37°C = {celsius_to_fahrenheit(37):.1f}°F")
练习5:计算平均数
编写一个函数,计算列表中所有数的平均数。
数学公式:
平均值 = (所有数的和) / (数的个数)
查看答案
def calculate_average(numbers):
"""计算平均数"""
if len(numbers) == 0:
return 0
return sum(numbers) / len(numbers)
# 测试
scores = [85, 92, 78, 95, 88]
average = calculate_average(scores)
print(f"平均分: {average:.1f}")
# 另一个例子
heights = [1.65, 1.72, 1.68, 1.75, 1.70]
avg_height = calculate_average(heights)
print(f"平均身高: {avg_height:.2f}米")
练习6:幂函数
编写一个递归函数,计算x的n次方。
数学定义:
xⁿ = x × x × ... × x (共n个x相乘)
递归定义:
xⁿ = x × xⁿ⁻¹ (当n > 0时)
x⁰ = 1 (基准情况)
查看答案
def power(x, n):
"""计算x的n次方"""
if n == 0:
return 1
return x * power(x, n - 1)
# 测试
print(f"2³ = {power(2, 3)}") # 输出: 8
print(f"3⁴ = {power(3, 4)}") # 输出: 81
print(f"5⁰ = {power(5, 0)}") # 输出: 1
# 验证:用Python的**运算符
print(f"\n验证:")
print(f"2**10 = {power(2, 10)}") # 输出: 1024
print(f"10**3 = {power(10, 3)}") # 输出: 1000
实践练习
练习1:基本函数
编写一个函数,接收一个名字作为参数,打印出“你好,[名字]!“
查看答案
def greet(name):
print(f"你好,{name}!")
greet("小明")
greet("小红")
练习2:带参数的函数
编写一个函数,接收三个参数:宽、高和颜色,画出一个填充的矩形。
查看答案
import turtle
t = turtle.Pen()
def draw_rectangle(width, height, color):
t.color(color)
t.begin_fill()
for i in range(2):
t.forward(width)
t.left(90)
t.forward(height)
t.left(90)
t.end_fill()
draw_rectangle(100, 50, "red")
练习3:带返回值的函数
编写一个函数,接收一个数字作为参数,返回这个数字的平方。
查看答案
def square(x):
return x * x
result = square(5)
print(result) # 输出: 25
练习4:多个返回值
编写一个函数,接收一个矩形的宽和高,返回矩形的面积和周长。
查看答案
def rectangle_info(width, height):
area = width * height
perimeter = 2 * (width + height)
return area, perimeter
a, p = rectangle_info(10, 5)
print(f"面积: {a}, 周长: {p}")
练习5:默认参数
编写一个函数,画一个正六边形,默认边长为50,默认颜色为蓝色。
查看答案
import turtle
t = turtle.Pen()
def draw_hexagon(size=50, color="blue"):
t.color(color)
t.begin_fill()
for i in range(6):
t.forward(size)
t.left(60)
t.end_fill()
# 使用默认值
draw_hexagon()
t.penup()
t.goto(100, 0)
t.pendown()
# 使用自定义值
draw_hexagon(80, "red")
turtle.done()
练习6:画螺旋图案
编写一个函数,画一个螺旋图案。
查看答案
import turtle
t = turtle.Pen()
t.speed(0)
def draw_spiral(lines, length, angle, increment):
"""画螺旋图案"""
for i in range(lines):
t.forward(length + i * increment)
t.left(angle)
draw_spiral(50, 5, 90, 2)
turtle.done()
练习7:计算器函数
编写一个计算器函数,接收三个参数:第一个数字、操作符、第二个数字,返回计算结果。
查看答案
def calculate(num1, operator, num2):
if operator == "+":
return num1 + num2
elif operator == "-":
return num1 - num2
elif operator == "*":
return num1 * num2
elif operator == "/":
if num2 != 0:
return num1 / num2
else:
return "错误:除数不能为0"
else:
return "错误:不支持的操作符"
# 测试
print(calculate(10, "+", 5)) # 输出: 15
print(calculate(10, "-", 5)) # 输出: 5
print(calculate(10, "*", 5)) # 输出: 50
print(calculate(10, "/", 5)) # 输出: 2.0
练习8:递归求和
编写一个递归函数,计算从1到n的和。
查看答案
def sum_to_n(n):
"""递归计算1到n的和"""
# 退出条件
if n == 1:
return 1
# 递归调用
return n + sum_to_n(n - 1)
print(sum_to_n(5)) # 输出: 15 (1+2+3+4+5)
print(sum_to_n(10)) # 输出: 55
练习9:递归幂运算
编写一个递归函数,计算x的n次方。
查看答案
def power(x, n):
"""递归计算x的n次方"""
# 退出条件
if n == 0:
return 1
# 递归调用
return x * power(x, n - 1)
print(power(2, 3)) # 输出: 8 (2*2*2)
print(power(3, 4)) # 输出: 81 (3*3*3*3)
练习10:画多彩图案
编写一个函数,画一个多彩的圆形图案。
查看答案
import turtle
t = turtle.Pen()
t.speed(0)
turtle.bgcolor("black")
colors = ["red", "yellow", "blue", "green", "orange", "purple"]
def draw_colorful_circle(size, colors):
"""画多彩圆形图案"""
for i in range(len(colors)):
t.color(colors[i])
t.begin_fill()
t.circle(size)
t.end_fill()
t.left(360 / len(colors))
draw_colorful_circle(100, colors)
turtle.done()
综合项目:图形绘制系统
结合所学的知识,创建一个图形绘制系统:
import turtle
t = turtle.Pen()
t.speed(0)
def draw_square(size, color, x=0, y=0):
"""画正方形"""
t.penup()
t.goto(x, y)
t.pendown()
t.color(color)
t.begin_fill()
for i in range(4):
t.forward(size)
t.left(90)
t.end_fill()
def draw_triangle(size, color, x=0, y=0):
"""画三角形"""
t.penup()
t.goto(x, y)
t.pendown()
t.color(color)
t.begin_fill()
for i in range(3):
t.forward(size)
t.left(120)
t.end_fill()
def draw_circle(radius, color, x=0, y=0):
"""画圆形"""
t.penup()
t.goto(x, y - radius)
t.pendown()
t.color(color)
t.begin_fill()
t.circle(radius)
t.end_fill()
def draw_star(size, color, x=0, y=0):
"""画五角星"""
t.penup()
t.goto(x, y)
t.pendown()
t.color(color)
t.begin_fill()
for i in range(5):
t.forward(size)
t.right(144)
t.end_fill()
# 使用函数绘制图案
def draw_house():
"""画房子"""
# 房子主体
draw_square(100, "brown", -50, -50)
# 屋顶
draw_triangle(120, "red", -60, 50)
# 门
draw_square(30, "yellow", -15, -50)
# 窗户
draw_square(20, "lightblue", -40, -20)
draw_square(20, "lightblue", 20, -20)
def draw_flower_garden():
"""画花园"""
flowers = [
(-100, -100, "red"),
(-50, -120, "yellow"),
(0, -100, "purple"),
(50, -120, "pink"),
(100, -100, "orange")
]
for x, y, color in flowers:
draw_star(20, color, x, y)
def draw_scene():
"""画完整场景"""
# 画天空
draw_circle(50, "yellow", -150, 150) # 太阳
# 画房子
draw_house()
# 画花园
draw_flower_garden()
# 绘制场景
draw_scene()
turtle.done()
章节小结
核心知识点
-
函数的基本概念:
- 函数是可重复使用的代码块
- Python函数和数学函数非常相似
- 都有:名字、参数、处理过程、返回值
- 定义函数使用
def关键字,调用函数使用函数名和括号
-
数学函数 vs Python函数:
- 数学函数: f(x) = x²
- Python函数: def f(x): return x * x
- 参数就像数学函数的自变量
- 返回值就像数学函数的因变量/函数值
-
函数的参数:
- 参数让函数更灵活
- 可以有多个参数
- 可以设置默认参数值
- 实参按位置对应到参数(像代入数学函数的数值)
-
函数的返回值:
- 使用
return语句返回值(类似数学函数计算结果) - 返回值可以在程序中使用
- 可以返回多个值
- 可以把数学公式转换成Python函数
- 使用
-
变量的作用域:
- 局部变量:函数内部定义,只在函数内有效
- 全局变量:函数外部定义,在整个程序有效
- 使用
global关键字修改全局变量
-
递归函数:
- 函数调用自身(类似数学归纳法)
- 必须有退出条件(基准情况)
- 每次调用参数要变化
- 常见应用:阶乘、斐波那契数列、求和
-
文档字符串:
- 用来说明函数功能
- 使用
help()查看
数学知识回顾
本章涉及的重要数学概念:
- 函数概念:输入→处理→输出
- 绝对值: |x|
- 线性函数: f(x) = ax + b
- 几何公式:矩形面积/周长、圆面积/周长、三角形面积
- 阶乘: n! = n × (n-1) × … × 1
- 等差数列求和: S(n) = n(n+1)/2
- 斐波那契数列: F(n) = F(n-1) + F(n-2)
- 最大公约数和最小公倍数
- 素数判断
- 温度转换公式
重要概念
- 函数提高了代码的复用性
- 函数让代码更易读、易维护
- 参数是函数的输入(像数学函数的自变量)
- 返回值是函数的输出(像数学函数的因变量)
- 递归必须有退出条件(基准情况)
- Python函数是数学函数在编程中的实现
- 可以用Python验证和探索数学概念
常见错误和调试
错误1:忘记定义函数
# 错误:直接调用未定义的函数
draw_square()
# 正确:先定义,再调用
def draw_square():
...
draw_square()
错误2:参数数量不匹配
def greet(name, age):
print(f"我叫{name},{age}岁")
# 错误:参数数量不对
greet("小明") # TypeError: greet() missing 1 required positional argument
# 正确:提供所有参数
greet("小明", 12)
错误3:混淆定义和调用
# 错误:忘记括号
def greet():
print("你好")
greet # 这只是函数名,不会调用
# 正确:使用括号调用
greet() # 这才是调用函数
错误4:递归没有退出条件
# 错误:没有退出条件,会导致无限递归
def count_down(n):
print(n)
count_down(n - 1)
count_down(5) # 最终会报错:RecursionError
# 正确:添加退出条件
def count_down(n):
print(n)
if n > 1: # 退出条件
count_down(n - 1)
调试技巧
- 打印调试:
def my_function(x):
print(f"函数收到参数: {x}") # 检查参数
result = x * 2
print(f"函数计算结果: {result}") # 检查结果
return result
- 检查返回值:
result = my_function(5)
print(f"返回值是: {result}")
- 使用
type()检查类型:
print(type(result)) # 确认返回值类型
给家长的小贴士:函数的错误通常比较隐蔽,建议在调试时多使用print()语句,逐步检查函数的执行过程。
挑战练习
挑战1:改进画图函数
改进前面的图形绘制系统,添加更多图形(如菱形、六边形等),并让函数支持边框颜色和填充颜色分开设置。
提示
可以添加参数,如fill_color和border_color。
挑战2:编写成绩等级函数
编写一个函数,接收分数作为参数,返回等级(A/B/C/D/F)。
提示
使用条件语句判断分数范围。
挑战3:递归画图
编写一个递归函数,画一个更复杂的分形图案(如谢尔宾斯基三角形)。
提示
可以画三个小三角形,每个在大三角形的顶点处。
下一步
恭喜你完成了函数的学习!现在你已经掌握了:
✅ 变量和数据类型 ✅ 条件语句和循环语句 ✅ 列表和字典 ✅ 函数和递归 ✅ 用Python实现数学函数
数学与编程的联系
通过这一章,你发现了Python函数和数学函数有很多相似之处:
-
函数结构:
- 数学: f(x) = 2x + 1
- Python: def f(x): return 2*x + 1
-
参数和返回值:
- 参数就像数学函数的自变量
- 返回值就像数学函数的因变量
-
函数的应用:
- 数学:描述数量关系和变化规律
- Python:实现计算逻辑和数据处理
用Python学习数学
现在你可以用Python来:
- 验证数学计算
- 探索数学规律(比如斐波那契数列)
- 实现数学公式
- 可视化数学概念
继续探索:
- 尝试用Python实现更多数学公式
- 探索数列、函数图像等数学概念
- 用编程解决数学问题
这些是Python编程的核心基础知识。下一章,我们将学习库(Library),这将让我们的程序变得更加强大。
库就像是Python的“工具箱“,里面装满了别人已经写好的功能,我们可以直接使用,而不需要自己从头开始写。比如:
math库:提供各种数学函数(三角函数、对数等)random库:生成随机数turtle库:画图
这将大大扩展我们的编程能力!
继续加油,你正在成为一名优秀的程序员!🎉