Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第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函数:接收一些数据,执行代码,返回结果

它们都有:

  1. 一个名字(比如f、g、draw_square)
  2. 输入(参数)
  3. 处理过程(计算或代码)
  4. 输出(返回值)

给家长的小贴士:

  • 如果孩子已经学过数学函数,可以用数学函数作为类比,这样孩子会更容易理解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 + bdef 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()

默认参数的规则

  1. 默认参数必须在非默认参数之后
  2. 调用函数时,可以只给部分参数赋值
# 错误的例子
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()

递归函数

什么是递归

递归是指函数调用自身。听起来很奇怪,但这是一个非常强大的编程技巧。

递归就像数学归纳法

如果你学过数学归纳法,递归的概念就很相似了:

数学归纳法证明:

  1. 基准情况:证明当n=1时命题成立
  2. 归纳假设:假设当n=k时命题成立
  3. 归纳递推:证明当n=k+1时命题也成立

递归函数:

  1. 基准情况:最简单的情况,直接返回结果
  2. 递归调用:调用自身解决更小的问题
  3. 递归推进:每次调用要朝着基准情况前进

递归的要素

编写递归函数时,必须注意以下几点:

  1. 必须有退出条件(基准情况)
  2. 每次调用时,参数要发生变化
  3. 参数变化要朝着退出条件的方向进行

递归示例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()

章节小结

核心知识点

  1. 函数的基本概念:

    • 函数是可重复使用的代码块
    • Python函数和数学函数非常相似
    • 都有:名字、参数、处理过程、返回值
    • 定义函数使用def关键字,调用函数使用函数名和括号
  2. 数学函数 vs Python函数:

    • 数学函数: f(x) = x²
    • Python函数: def f(x): return x * x
    • 参数就像数学函数的自变量
    • 返回值就像数学函数的因变量/函数值
  3. 函数的参数:

    • 参数让函数更灵活
    • 可以有多个参数
    • 可以设置默认参数值
    • 实参按位置对应到参数(像代入数学函数的数值)
  4. 函数的返回值:

    • 使用return语句返回值(类似数学函数计算结果)
    • 返回值可以在程序中使用
    • 可以返回多个值
    • 可以把数学公式转换成Python函数
  5. 变量的作用域:

    • 局部变量:函数内部定义,只在函数内有效
    • 全局变量:函数外部定义,在整个程序有效
    • 使用global关键字修改全局变量
  6. 递归函数:

    • 函数调用自身(类似数学归纳法)
    • 必须有退出条件(基准情况)
    • 每次调用参数要变化
    • 常见应用:阶乘、斐波那契数列、求和
  7. 文档字符串:

    • 用来说明函数功能
    • 使用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)

调试技巧

  1. 打印调试:
def my_function(x):
    print(f"函数收到参数: {x}")  # 检查参数
    result = x * 2
    print(f"函数计算结果: {result}")  # 检查结果
    return result
  1. 检查返回值:
result = my_function(5)
print(f"返回值是: {result}")
  1. 使用type()检查类型:
print(type(result))  # 确认返回值类型

给家长的小贴士:函数的错误通常比较隐蔽,建议在调试时多使用print()语句,逐步检查函数的执行过程。


挑战练习

挑战1:改进画图函数

改进前面的图形绘制系统,添加更多图形(如菱形、六边形等),并让函数支持边框颜色和填充颜色分开设置。

提示

可以添加参数,如fill_colorborder_color

挑战2:编写成绩等级函数

编写一个函数,接收分数作为参数,返回等级(A/B/C/D/F)。

提示

使用条件语句判断分数范围。

挑战3:递归画图

编写一个递归函数,画一个更复杂的分形图案(如谢尔宾斯基三角形)。

提示

可以画三个小三角形,每个在大三角形的顶点处。


下一步

恭喜你完成了函数的学习!现在你已经掌握了:

✅ 变量和数据类型 ✅ 条件语句和循环语句 ✅ 列表和字典 ✅ 函数和递归用Python实现数学函数

数学与编程的联系

通过这一章,你发现了Python函数和数学函数有很多相似之处:

  1. 函数结构:

    • 数学: f(x) = 2x + 1
    • Python: def f(x): return 2*x + 1
  2. 参数和返回值:

    • 参数就像数学函数的自变量
    • 返回值就像数学函数的因变量
  3. 函数的应用:

    • 数学:描述数量关系和变化规律
    • Python:实现计算逻辑和数据处理

用Python学习数学

现在你可以用Python来:

  • 验证数学计算
  • 探索数学规律(比如斐波那契数列)
  • 实现数学公式
  • 可视化数学概念

继续探索:

  • 尝试用Python实现更多数学公式
  • 探索数列、函数图像等数学概念
  • 用编程解决数学问题

这些是Python编程的核心基础知识。下一章,我们将学习库(Library),这将让我们的程序变得更加强大。

库就像是Python的“工具箱“,里面装满了别人已经写好的功能,我们可以直接使用,而不需要自己从头开始写。比如:

  • math库:提供各种数学函数(三角函数、对数等)
  • random库:生成随机数
  • turtle库:画图

这将大大扩展我们的编程能力!

继续加油,你正在成为一名优秀的程序员!🎉