当前位置:首页>python>python笔记系列之——函数

python笔记系列之——函数

  • 2026-09-24 22:07:28
python笔记系列之——函数

小朋友们,你们好!欢迎来到Python魔法课堂。今天我们要学习一个超级厉害的工具——函数!

你有没有遇到过这样的情况:写代码时,有一段相同的操作要重复很多次?比如,你要计算好几个长方形的面积,每次都要写 长 * 宽,是不是又累又容易写错?要是能有一个“小机器人”,你只要告诉它长和宽,它就能自动算出面积,那该多好呀!

在Python里,这个“小机器人”就叫函数。函数可以把一段代码打包起来,给它起个名字,然后随时喊它帮忙。学会了函数,你的代码就会变得像搭积木一样,又简单又有趣!

准备好了吗?让我们打开今天的魔法宝箱吧!


一、第一个魔法盒:定义和调用函数

想象你有一个魔法盒,你只要对它念一句咒语,它就会自动帮你做一件事。在Python里,这个魔法盒就是函数。

1. 怎么造一个魔法盒?

造魔法盒的咒语是 def(define 的缩写)。格式如下:

def 魔法盒的名字():    要做的事情

比如,我们造一个会打招呼的魔法盒:

def say_hello():    print("你好呀,朋友!")

这个魔法盒的名字叫 say_hello,它里面只放了一句话:打印“你好呀,朋友!”。

2. 怎么使用魔法盒?

魔法盒造好之后,不会自己动,你需要“叫醒”它。叫醒它的方法就是写出它的名字,后面加上括号 ()。

say_hello()   # 调用函数

运行后,屏幕上就会显示:

你好呀,朋友!

你可以叫它很多次,它每次都会乖乖执行里面的代码。

试试看:定义一个函数 print_favorite_food(),里面打印一句“我最喜欢吃披萨!”,然后调用它三次。


二、给魔法盒喂原料:函数的参数

上面的魔法盒每次只会做同样的事,有点死板。如果能让它根据我们给的不同原料做出不同反应,那就更棒了!这些“原料”就是参数。

1. 必填参数:一个都不能少

我们可以在定义函数时,在括号里写上参数的名字。调用时,必须按顺序提供对应数量的原料。

def greet(name):    print(f"你好,{name}!")greet("小明")   # 输出:你好,小明!greet("小红")   # 输出:你好,小红!# greet()      # 报错,因为缺少参数

如果函数需要多个原料,就写多个参数,用逗号隔开。

def add(a, b):    result = a + b    print(f"{a} + {b} = {result}")add(3, 5)   # 输出:3 + 5 = 8

注意:参数的顺序很重要。add(5, 3) 会把5给a,3给b,结果还是8,但如果两个参数作用不同,顺序就不能乱。

试试看:定义一个函数 multiply(x, y),打印 x 和 y 的乘积,然后调用它计算 4×7。

2. 默认参数:有备无患

有时候,某些原料大部分时候都一样,只有偶尔不同。我们可以给参数设置一个默认值。这样,如果调用时没给这个原料,就会自动使用默认值。

def greet(name, greeting="你好"):    print(f"{greeting},{name}!")greet("小明")            # 输出:你好,小明!greet("小红", "哈喽")    # 输出:哈喽,小红!

注意:默认参数必须放在必填参数的后面,否则Python会糊涂。

# 错误示例def greet(greeting="你好", name):   # 这样不行!    ...

试试看:定义一个函数 introduce(name, age=10),打印“我叫xx,今年xx岁”。如果不给年龄,默认10岁。

3. 关键字参数:打乱顺序也不怕

调用函数时,你可以用“参数名=值”的形式指定参数,这叫关键字参数。这样,你可以不按照定义时的顺序传递原料,非常自由。

def introduce(name, age, city):    print(f"我叫{name},今年{age}岁,住在{city}。")# 以下三种调用方式都正确introduce("小明", 10, "北京")introduce(city="北京", name="小明", age=10)introduce("小明", city="北京", age=10)

注意:关键字参数必须写在普通参数的后面。

# 错误示例introduce(city="北京", "小明", age=10)   # 语法错误

试试看:调用上面的 introduce 函数,用关键字参数把顺序打乱,看看结果。

4. 不定长参数:我不知道会有多少原料

有时候,你希望函数能接收任意多个原料,比如计算一堆数字的总和。这时可以用 *args。

*args 会把所有额外的位置参数打包成一个元组(你可以把它想象成一个列表)。

def sum_all(*numbers):    total = 0    for n in numbers:        total += n    print(f"总和是:{total}")sum_all(1, 2, 3)        # 输出:总和是:6sum_all(10, 20, 30, 40) # 输出:总和是:100

如果你还需要接收任意多个关键字参数,可以用 **kwargs。它会把额外的关键字参数打包成一个字典。

def show_info(**info):    for key, value in info.items():        print(f"{key} -> {value}")show_info(name="小明", age=10, hobby="编程")

输出:

name -> 小明age -> 10hobby -> 编程

试试看:定义一个函数 average(*scores),计算传入的所有分数的平均值,并打印。


三、魔法盒的产出:返回值

我们的魔法盒不仅能做事,还能返回结果给你。比如,你给魔法盒两个数字,它算好和之后,把结果交到你手里。这就要用到 return 语句。

def add(a, b):    return a + bresult = add(5, 3)print(result)   # 输出 8

重要规则:

  • return 会立刻结束函数,后面的代码不会执行。

  • 如果一个函数没有写 return,它默认返回 None(表示“什么都没有”)。

def say_hi():    print("嗨")    return    print("这行永远不会执行")   # 被忽略x = say_hi()print(x)   # 输出 None

试试看:写一个函数 is_even(n),如果 n 是偶数返回 True,否则返回 False。


四、变量的地盘:作用域

每个变量都有自己的“地盘”,有的只能在函数内部使用,有的可以在整个程序中使用。这叫做作用域。

1. 局部变量:只在函数内部生效

在函数内部定义的变量,就是局部变量,外面无法访问。

def test():    x = 10   # 局部变量    print(x)test()print(x)   # 报错!x 在外面不可见

为什么要分地盘?
这样可以避免函数内部的变量不小心影响到程序的其他部分,就像每个小朋友有自己的玩具箱,不会混在一起。

练习1:下面的代码会输出什么?试着运行一下。

def func():    a = 5    print(a)func()print(a)   # 这里会怎样?

练习2:写一个函数 my_secret(),在里面定义一个局部变量 secret = "我喜欢编程",然后在函数内部打印它。在函数外面也尝试打印这个变量,看看会发生什么。

2. 全局变量:到处都能用

在函数外部定义的变量,就是全局变量。在函数内部,你可以读取它。

y = 20   # 全局变量def show():    print(y)   # 可以读取show()   # 输出 20

但是,如果想在函数内部修改全局变量,需要先声明 global。

y = 20def change():    global y   # 告诉Python:我要修改全局变量y    y = 100change()print(y)   # 输出 100

如果不加 global,在函数内部给同名变量赋值,会创建一个新的局部变量,不会影响全局变量。

z = 30def try_change():    z = 50   # 这是局部变量,不是全局的    print("函数内:", z)try_change()   # 输出 函数内: 50print("全局:", z)   # 输出 30

练习3:写一个全局变量 score = 100,定义一个函数 add_score(),它让 score 增加10,然后打印新分数。注意要用 global。

练习4:下面的代码输出什么?为什么?

x = 10def test():    x = 20    print(x)test()print(x)

练习5:猜一猜输出。

a = 5def func():    global a    a = a + 1    print(a)func()print(a)

练习6:写一个程序,有一个全局变量 total = 0。定义两个函数:add() 让 total 增加任意指定的数值;show() 打印 total 的当前值。然后依次调用 add(5), add(3), show(),观察结果。

3. 嵌套函数中的 nonlocal

当函数里面再定义一个函数时,内层函数如果想修改外层函数的变量,需要用 nonlocal。

def outer():    x = 10    def inner():        nonlocal x        x += 1        print(x)    inner()outer()   # 输出 11

如果不写 nonlocal,内层函数只能读取,不能修改外层变量(会创建一个新的局部变量)。

练习7:写一个函数 counter(),里面定义一个变量 count = 0,再定义一个内部函数 increment(),每次调用 increment() 就让 count 加1并打印。最后让 counter() 返回 increment。然后测试:c = counter(),然后多次调用 c()。

练习8:下面代码会输出什么?为什么?

def outer():    msg = "Hello"    def inner():        msg = "Hi"        print(msg)    inner()    print(msg)outer()

五、函数自己叫自己:递归

有一种特殊的函数,它会在自己的肚子里调用自己。这就像镜子里的镜子,一层套一层。这种函数叫递归函数。

递归必须有一个结束条件(也叫基线条件),否则会无限循环下去,直到程序崩溃。

1. 递归的经典例子:计算阶乘

阶乘:n! = n × (n-1) × (n-2) × ... × 1,并且规定 0! = 1。

def factorial(n):    if n == 0 or n == 1:   # 结束条件        return 1    else:        return n * factorial(n-1)print(factorial(5))   # 输出 120(5×4×3×2×1)

它是怎么工作的?
我们可以画出“调用栈”:

  • factorial(5) 想要结果,就去问 factorial(4)

  • factorial(4) 去问 factorial(3)

  • factorial(3) 去问 factorial(2)

  • factorial(2) 去问 factorial(1)

  • factorial(1) 直接返回 1

  • 然后一层层返回:1 → 2 → 6 → 24 → 120

练习9:手动模拟 factorial(4) 的计算过程,写出每一步的返回值。

2. 另一个经典例子:斐波那契数列

斐波那契数列:1, 1, 2, 3, 5, 8, 13, ... 其中第一个和第二个都是1,后面的每个数都是前两个数之和。

def fib(n):    if n == 1 or n == 2:        return 1    else:        return fib(n-1) + fib(n-2)print(fib(6))   # 输出 8(数列:1,1,2,3,5,8)

注意:这种写法虽然简单,但效率很低,因为会重复计算很多次。比如 fib(5) 会计算 fib(4) 和 fib(3),而 fib(4) 又会计算 fib(3) 和 fib(2),fib(3) 被算了两次。我们后面会学优化方法(比如记忆化)。

练习10:用递归函数计算斐波那契数列的第10项,然后自己验证是否正确。

3. 递归画图:谢尔宾斯基三角形(选读)

递归不只是用来算数字,还可以用来画图。比如画一个“谢尔宾斯基三角形”——一个大三角形里面挖掉一个倒着的小三角形,剩下的三个小三角形再重复这个过程。

import turtledef sierpinski(t, length, depth):    if depth == 0:        for _ in range(3):            t.forward(length)            t.left(120)    else:        sierpinski(t, length/2, depth-1)        t.forward(length/2)        sierpinski(t, length/2, depth-1)        t.backward(length/2)        t.left(60)        t.forward(length/2)        t.right(60)        sierpinski(t, length/2, depth-1)        t.left(60)        t.backward(length/2)        t.right(60)t = turtle.Turtle()t.speed(0)sierpinski(t, 200, 3)turtle.done()

这个例子比较难,可以先跳过,只是让你感受递归的威力。

4. 递归的注意事项

  • 必须有结束条件,否则会无限递归,导致 RecursionError。

  • Python默认递归深度大约1000,所以深度太大的递归(比如 factorial(2000))会报错。你可以用 sys.setrecursionlimit(3000) 临时增加深度,但不推荐。

  • 有些问题用循环(迭代)解决更高效,比如阶乘也可以用循环写。

练习11:用递归写一个函数 power(base, exp),计算 base 的 exp 次方(exp是自然数)。例如 power(2, 3) 返回 8。

练习12:用递归写一个函数 sum_range(start, end),返回从 start 到 end 的所有整数的和(包括两端)。例如 sum_range(1, 5) 返回 15。

练习13:用递归写一个函数 reverse_string(s),返回字符串 s 的反转。例如 reverse_string("hello") 返回 "olleh"。提示:如果字符串长度为0或1,直接返回;否则返回 最后一个字符 + reverse_string(除了最后一个字符的字符串)。

练习14:用递归判断一个字符串是否是回文(正反一样)。例如 is_palindrome("level") 返回 True。提示:比较第一个和最后一个字符,然后递归判断去掉两端后的子串。

练习15:写一个递归函数 draw_line(n),打印 n 个星号。例如 draw_line(5) 打印 *****。然后再写一个递归函数 draw_triangle(n),打印一个由星号组成的直角三角形,行数为 n。例如 draw_triangle(4) 输出:

**********

练习16:汉诺塔问题。有三根柱子 A、B、C,A 上有 n 个盘子(从小到大叠放)。要把所有盘子从 A 移到 C,每次只能移动一个盘子,且大盘子不能压在小盘子上。写一个递归函数 hanoi(n, start, end, helper),打印每一步的移动步骤。例如 hanoi(3, "A", "C", "B") 会输出 7 步。这是递归的经典难题,试试看!


六、一句话函数:lambda

有些函数特别简单,只有一行表达式。Python允许我们用一种更简洁的方式定义它们,叫做lambda(匿名函数)。

1. lambda 的基本写法

语法:

lambda 参数1, 参数2, ... : 表达式

例如,一个求两数之和的函数:

add = lambda a, b: a + bprint(add(3, 5))   # 输出 8

注意:

  • lambda 后面直接写参数,没有括号。

  • 冒号后面只能写一个表达式,不能写多行语句(比如不能有 print、for 循环、if 语句块等)。但可以使用条件表达式(x if condition else y)。

  • lambda 会自动返回表达式的值,不需要写 return。

2. lambda 的常用场景

lambda 通常用在需要临时小函数的地方,比如排序、过滤、映射等。

2.1 与 sorted() 结合

按年龄对学生列表排序:

students = [("小明", 10), ("小红", 9), ("小刚", 11)]students.sort(key=lambda s: s[1])  # 按年龄排序print(students)   # [('小红', 9), ('小明', 10), ('小刚', 11)]

按名字长度排序:

words = ["apple", "pear", "banana", "kiwi"]words.sort(key=lambda w: len(w))print(words)   # ['pear', 'kiwi', 'apple', 'banana']

2.2 与 filter() 结合(选读)

filter() 用来筛选列表中的元素。它需要两个参数:一个判断函数(返回 True/False),一个可迭代对象。

numbers = [1, 2, 3, 4, 5, 6]even_numbers = list(filter(lambda x: x % 2 == 0, numbers))print(even_numbers)   # [2, 4, 6]

2.3 与 map() 结合

map() 用来对列表中的每个元素应用一个函数,返回新列表。

numbers = [1, 2, 3, 4]squares = list(map(lambda x: x**2, numbers))print(squares)   # [1, 4, 9, 16]

2.4 在条件表达式中使用

lambda 可以结合 if-else 条件表达式,但注意这是表达式,不是语句。

max = lambda a, b: a if a > b else bprint(max(5, 8))   # 输出 8

3. lambda 的局限性

  • 不能包含循环(如 for, while)。

  • 不能包含赋值语句(如 x = 5)。

  • 不能包含多行代码。

  • 没有自己的函数名,调试时不太方便。

如果逻辑超过一行,最好还是用 def 定义普通函数。

练习17:用 lambda 写一个函数 is_positive(x),返回 x 是否大于0。

练习18:有一个列表 [3, 8, 1, 6, 5],用 sorted() 和 lambda 按数字的个位数排序。

练习19:用 filter() 和 lambda 筛选出列表中所有长度大于3的字符串。列表:["cat", "elephant", "dog", "bird"]。

练习20:用 map() 和 lambda 把列表 [1,2,3,4] 的每个元素变成它的立方。

练习21:写一个 lambda 表达式 my_max,接收任意多个参数(用 *args),返回其中的最大值。提示:*args 在 lambda 中也可以使用。


七、高手进阶:冷门但有趣的知识

当你对函数越来越熟悉后,会发现它们还有很多隐藏的魔法。下面我们详细讲解这些“高手技巧”。

1. 函数也是对象

在Python里,函数和其他数据(数字、字符串)一样,可以被赋值给变量、作为参数传递、作为返回值。

def hello():    print("Hello")f = hello   # 把函数赋值给变量ff()         # 调用f,输出 Hello

你甚至可以把函数放在列表里:

def add(a, b): return a + bdef sub(a, b): return a - bops = [add, sub]print(ops[0](5, 3))   # 输出 8

练习22:写一个函数 apply(func, x, y),它接收一个函数 func 和两个数字,然后返回 func(x, y)。然后调用 apply(lambda a,b: a*b, 4, 5),看看结果。

2. 文档字符串(docstring)

在函数的第一行用三个引号写一段文字,就可以用 help() 查看。这叫文档字符串,是给使用者看的说明书。

def multiply(a, b):    """返回 a 和 b 的乘积"""    return a * bhelp(multiply)   # 会显示函数名和说明

多行文档字符串示例:

def complex_func(x, y):    """    这是一个复杂函数的说明。    参数:        x: 第一个数字        y: 第二个数字    返回:        两个数字的某种运算结果    """    return x ** y

练习23:给你之前写的某个函数加上文档字符串,然后调用 help 查看效果。

3. 类型注解(Type Hints)—— 给变量贴标签

Python 是动态类型语言,变量的类型可以随时改变。但为了代码更清晰、更容易发现错误,Python 3.5 引入了类型注解。你可以给参数和返回值加上类型提示,但这些提示不会强制检查,只是给程序员看的(也可以被一些工具如 mypy 用来做静态检查)。

3.1 基本语法

def 函数名(参数1: 类型, 参数2: 类型) -> 返回值类型:    ...

例子:

def add(a: int, b: int) -> int:    return a + bresult = add(3, 5)print(result)

这里的 : int 表示 a 和 b 应该是整数,-> int 表示返回值应该是整数。即使你传入字符串,Python 也不会报错,但阅读代码的人就知道你的意图。

3.2 常见的类型

  • int:整数

  • float:浮点数

  • str:字符串

  • bool:布尔值

  • list:列表(可以指定元素类型,如 list[int])

  • tuple:元组

  • dict:字典(如 dict[str, int] 表示键是字符串,值是整数)

  • Optional:表示可以是该类型或 None(如 Optional[int])

  • Any:任意类型

3.3 对列表、字典等容器指定内部类型

需要从 typing 模块导入 List, Dict, Tuple, Optional 等。

from typing import List, Dict, Tupledef sum_list(numbers: List[int]) -> int:    return sum(numbers)def get_student() -> Dict[str, int]:    return {"age": 10, "score": 95}def divide(a: int, b: int) -> Tuple[int, int]:    return (a // b, a % b)

3.4 默认参数的类型注解

默认参数也可以加类型,写法与普通参数一样。

def greet(name: str, greeting: str = "你好") -> None:    print(f"{greeting},{name}!")

注意:返回值是 None 时写 -> None。

3.5 类型别名

如果某个类型很复杂,可以给它起个外号。

from typing import ListStudent = List[str]   # Student 是字符串列表的别名def get_names() -> Student:    return ["小明", "小红"]

3.6 为什么需要类型注解?

  • 提高代码可读性:别人一看就知道参数和返回值的预期类型。

  • 帮助 IDE 提供更好的自动补全和错误提示。

  • 可以用工具(如 mypy)做静态检查,提前发现类型不匹配的错误。

练习24:给下面这个函数加上类型注解。

def multiply(a, b):    return a * b

练习25:写一个函数 make_person(name, age, city),返回一个字典,包含这三项信息。给参数和返回值加上类型注解。

练习26:写一个函数 filter_positive(numbers),接收一个整数列表,返回一个新列表,只包含正数。加上类型注解。

4. 嵌套函数(再探)与闭包

函数内部可以再定义函数。内部函数可以访问外部函数的变量,并且可以返回内部函数,这样就形成了闭包。闭包可以“记住”外部函数的变量值。

def outer(x):    def inner(y):        return x + y    return inneradd5 = outer(5)print(add5(3))   # 输出 8

这里 outer 返回了 inner,并且 inner 记住了 x=5。即使 outer 已经执行完毕,x 的值仍然保留在 add5 中。

练习27:写一个函数 make_multiplier(n),返回一个函数,这个函数接收一个参数 x,返回 x * n。例如 double = make_multiplier(2),然后 double(5) 应返回 10。

5. 小心默认参数的“陷阱”

如果默认参数是可变对象(比如列表、字典),多次调用可能会累积修改,因为默认值只在函数定义时计算一次,之后每次调用都使用同一个对象。

def add_item(item, lst=[]):    lst.append(item)    return lstprint(add_item(1))   # [1]print(add_item(2))   # [1, 2]  —— 不是 [2]!

解决方法:用 None 作为默认值,在函数内部创建新列表。

def add_item(item, lst=None):    if lst is None:        lst = []    lst.append(item)    return lst

练习28:找出下面代码的问题并修复。

def add_student(name, class_list=[]):    class_list.append(name)    return class_list

6. 解包参数:用 * 和 ** 拆散列表和字典

调用函数时,可以用 * 把一个列表拆成多个位置参数,用 ** 把一个字典拆成多个关键字参数。

def add(a, b, c):    return a + b + cnums = [1, 2, 3]print(add(*nums))   # 相当于 add(1,2,3)info = {"a": 10, "b": 20, "c": 30}print(add(**info))  # 相当于 add(a=10,b=20,c=30)

练习29:写一个函数 print_info(name, age, city),然后用一个字典 {"name":"小明", "age":10, "city":"北京"} 通过 ** 解包调用它。

7. 函数可以返回多个值(其实是返回一个元组)

def get_name_and_age():    return "小明", 10name, age = get_name_and_age()print(name, age)   # 小明 10

实际上返回的是一个元组 ("小明", 10),然后通过元组解包赋值给两个变量。

8. nonlocal 关键字(再巩固)

在嵌套函数中,如果想修改外层函数的变量,需要用 nonlocal。如果不写,Python会认为你在创建一个新的局部变量。

def outer():    x = 10    def inner():        nonlocal x        x += 1        print(x)    inner()outer()   # 输出 11

练习30:写一个函数 create_counter(),它返回一个内部函数,每次调用内部函数时,计数器加1并返回当前计数值。要求使用 nonlocal。

9. 函数属性

函数也可以有自己的属性,就像变量一样。你可以给函数添加自定义属性。

def say_hello():    print("Hello")say_hello.times_called = 0   # 给函数添加一个属性say_hello.times_called += 1print(say_hello.times_called)   # 输出 1

这个技巧可以用来统计函数被调用的次数,或者缓存一些信息。


八、综合大挑战

现在,你已经掌握了函数的各种魔法。来挑战几个小任务吧!

挑战1:计算器(带类型注解)

编写一个函数 calculator(a: float, b: float, op: str) -> float,根据 op (+, -, *, /) 返回计算结果。如果 op 不是这些符号,返回 None。如果除数为0,返回 None。

挑战2:斐波那契数列(记忆化递归)

普通的递归 fib 很慢,因为重复计算太多。请用“记忆化”(用一个字典保存已经计算过的值)来优化它。写一个函数 fib_memo(n, memo={})。

挑战3:任意多数字的平均值

写一个函数 average(*nums: float) -> float,返回所有数字的平均值。如果没传任何数字,返回 0.0。

挑战4:密码生成器(带类型注解和默认参数)

写一个函数 generate_password(length: int = 8, use_digits: bool = True, use_punctuation: bool = False) -> str,随机生成一个指定长度的密码。可以包含字母(大小写)、数字、标点符号(根据参数)。提示:使用 random 模块,string.ascii_letters, string.digits, string.punctuation。

挑战5:递归打印目录树(高级)

如果你学过了 os 模块,可以尝试写一个递归函数 list_files(path, indent=0),打印出指定文件夹下的所有文件和子文件夹,并用缩进表示层级。

挑战6:装饰器入门

写一个装饰器 timer,它接收一个函数,返回一个新函数。新函数在执行原函数之前记录开始时间,执行后记录结束时间,并打印耗时。(提示:使用 time.time() 和 *args, **kwargs)


九、总结

今天我们开启了一场函数大冒险,学到了:

  • 定义和调用:用 def 创建魔法盒,用 函数名() 使用它。

  • 参数:必填参数、默认参数、关键字参数、不定长参数 *args 和 **kwargs。

  • 返回值:用 return 把结果交给调用者。

  • 变量作用域:局部变量、全局变量(global)、嵌套函数中的 nonlocal。做了大量练习。

  • 递归:函数自己调用自己,必须有结束条件。通过阶乘、斐波那契、画图等例子深入理解,并完成了多个练习。

  • 匿名函数:lambda 一行小函数,常用于排序、过滤、映射。详细讲解了用法和局限性。

  • 类型注解:给参数和返回值添加类型提示,提高代码可读性,包括基本类型、容器类型、默认参数等。

  • 冷门技巧:函数是对象、文档字符串、嵌套函数与闭包、默认参数陷阱、解包参数、函数属性等。

函数让我们的代码变得像搭积木一样,每个小积木(函数)可以独立测试、反复使用。从今天起,试着把你常用的代码段改写成函数吧!

最后的最后:别忘了多动手练习,把每个练习都在电脑上敲一遍,观察结果。遇到错误不要怕,那是学习的最好机会!

最新文章

随机文章