Skip to content

Python 函数:从"重复劳动"到"一键搞定"的编程革命

引言:为什么需要函数?

想象你是一家奶茶店的老板,每天要制作 100 杯珍珠奶茶。如果每杯都要手动完成:烧水 → 泡茶 → 加奶 → 加糖 → 加珍珠 → 封口,你会累死。

更好的办法是:制定一个标准配方(函数),每次只需要按一下按钮(调用函数),机器自动完成所有步骤

在编程世界里,函数就是这个"标准配方"。它把一段重复使用的代码封装起来,起个名字,以后只需写名字就能执行整段代码。

今天,我们将彻底掌握函数的精髓,让你的代码从"手工作坊"升级为"自动化工厂"。


一、从重复到抽象:函数的诞生

1.1 问题的出现:代码重复

假设你要计算 3 个圆的面积:

python
r1 = 12.34
r2 = 9.08
r3 = 73.1

s1 = 3.14 * r1 * r1
s2 = 3.14 * r2 * r2
s3 = 3.14 * r3 * r3

问题 13.14 * x * x 写了 3 遍,很麻烦。

问题 2:如果要提高精度,把 3.14 改成 3.14159265359,需要改 3 个地方。如果计算 100 个圆呢?改 100 个地方?

1.2 函数的解决方案

python
def area_of_circle(r):
    return 3.14159265359 * r * r

s1 = area_of_circle(12.34)
s2 = area_of_circle(9.08)
s3 = area_of_circle(73.1)

生活化理解:函数就像奶茶店的"标准配方卡"——只需要写一次配方,店员每次按配方操作即可。要改配方?只改卡片,所有奶茶自动更新。

1.3 函数的核心价值:抽象

抽象是计算机科学的核心概念。它让我们忽略底层细节,关注高层逻辑

数学中的抽象

  • 不抽象:1 + 2 + 3 + ... + 100(写 100 个数字)
  • 抽象后:∑(n=1 to 100) n(一个符号搞定)

编程中的抽象

  • 不抽象:每次写 3.14 * r * r
  • 抽象后:area_of_circle(r)

生活化理解:就像开车——你不需要懂发动机原理,只需要会踩油门。函数就是你的"油门",踩下去就走,不用管内部怎么运转。


二、函数的定义与调用

2.1 定义函数:def 关键字

python
def 函数名(参数):
    """函数文档说明(可选)"""
    函数体
    return 返回值

逐部分解析

python
def greet(name):           # def + 函数名 + 参数列表
    """向指定的人打招呼"""    # 文档字符串(可选)
    message = f'你好,{name}!'  # 函数体
    return message           # 返回值(可选)

2.2 调用函数:写名字就行

python
# 定义
def greet(name):
    return f'你好,{name}!'

# 调用
result = greet('张三')
print(result)    # 你好,张三!

print(greet('李四'))    # 你好,李四!

生活化理解:定义函数像"注册公司"——准备好所有资源;调用函数像"开始营业"——真正使用这些资源。

2.3 函数的组成要素

要素说明示例
函数名标识符,遵循命名规则greet, calculate_area
参数输入,可以有多个或没有(name), (x, y), ()
函数体实现功能的代码块缩进的代码
返回值输出,用 return 返回return result
文档字符串说明函数功能"""这是说明"""

三、参数:函数的"输入口"

3.1 位置参数

python
def introduce(name, age, city):
    return f'{name}{age}岁,来自{city}'

# 按位置传参
print(introduce('张三', 25, '北京'))
# 张三,25岁,来自北京

注意:顺序很重要!

python
print(introduce('北京', 25, '张三'))    # 顺序错了,结果乱了

3.2 默认参数

python
def introduce(name, age, city='北京'):
    return f'{name}{age}岁,来自{city}'

# 不传 city,用默认值
print(introduce('张三', 25))           # 张三,25岁,来自北京

# 传 city,覆盖默认值
print(introduce('李四', 30, '上海'))   # 李四,30岁,来自上海

生活化理解:默认参数像"默认配置"——买手机默认 128G 存储,你可以加钱上 256G。

3.3 关键字参数

python
def introduce(name, age, city):
    return f'{name}{age}岁,来自{city}'

# 按名字传参,不用管顺序
print(introduce(city='北京', name='张三', age=25))
# 张三,25岁,来自北京

优点

  1. 不用记参数顺序
  2. 代码更清晰
  3. 可以跳过有默认值的参数

3.4 可变参数:*args

python
def sum_all(*numbers):
    total = 0
    for n in numbers:
        total = total + n
    return total

print(sum_all(1, 2))           # 3
print(sum_all(1, 2, 3, 4, 5))  # 15
print(sum_all())               # 0

生活化理解*numbers 像"任意数量的包裹"——不管寄几个,我都收。

3.5 关键字可变参数:**kwargs

python
def print_info(**info):
    for key, value in info.items():
        print(f'{key}: {value}')

print_info(name='张三', age=25, city='北京')
# name: 张三
# age: 25
# city: 北京

生活化理解**info 像"任意数量的标签"——不管贴几个标签,我都认。

3.6 参数组合

python
def complex_func(a, b, c=0, *args, **kwargs):
    print(f'a={a}, b={b}, c={c}')
    print(f'args={args}')
    print(f'kwargs={kwargs}')

complex_func(1, 2, 3, 4, 5, x=6, y=7)
# a=1, b=2, c=3
# args=(4, 5)
# kwargs={'x': 6, 'y': 7}

顺序规则:位置参数 → 默认参数 → *args**kwargs


四、返回值:函数的"输出口"

4.1 单个返回值

python
def square(x):
    return x * x

result = square(5)
print(result)    # 25

4.2 多个返回值

python
def get_user():
    name = '张三'
    age = 25
    city = '北京'
    return name, age, city    # 返回 tuple

# 解包接收
n, a, c = get_user()
print(n)    # 张三
print(a)    # 25

4.3 没有返回值

python
def say_hello():
    print('Hello!')
    # 没有 return,默认返回 None

result = say_hello()
print(result)    # None

4.4 return 的提前退出

python
def check_age(age):
    if age < 0:
        return '年龄不能为负'
    if age < 18:
        return '未成年'
    return '成年'

print(check_age(-5))    # 年龄不能为负
print(check_age(10))    # 未成年
print(check_age(20))    # 成年

注意:一旦执行 return,函数立即结束,后面的代码不再执行。


五、作用域:变量的"活动范围"

5.1 局部变量

python
def my_func():
    x = 10          # 局部变量,只在函数内有效
    print(x)

my_func()           # 10
print(x)            # NameError: name 'x' is not defined

生活化理解:局部变量像"家里的钥匙"——只在家里有效,出门就用不了。

5.2 全局变量

python
x = 10              # 全局变量

def my_func():
    print(x)        # 可以读取全局变量

my_func()           # 10

5.3 修改全局变量:global 关键字

python
count = 0

def increment():
    global count    # 声明使用全局变量
    count = count + 1

increment()
print(count)        # 1

注意:尽量不用 global,函数应该通过参数和返回值交流,而不是直接改全局变量。


六、常见误区与陷阱

6.1 误区一:忘记 return

python
# ❌ 错误:没有 return,默认返回 None
def add(a, b):
    a + b

result = add(1, 2)
print(result)    # None(不是3!)

# ✅ 正确
def add(a, b):
    return a + b

6.2 误区二:默认参数用可变对象

python
# ❌ 危险:默认参数只创建一次,多次调用共享
def add_item(item, items=[]):
    items.append(item)
    return items

print(add_item(1))    # [1]
print(add_item(2))    # [1, 2](不是预期的 [2]!)

# ✅ 正确:用 None 作为默认值
def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

6.3 误区三:函数名覆盖内置函数

python
# ❌ 危险:覆盖内置函数
def list():
    return [1, 2, 3]

my_list = list()    # 调用的是自定义函数,不是内置 list()
my_list.append(4)   # AttributeError

# ✅ 正确:避免使用内置函数名
def my_list_func():
    return [1, 2, 3]

6.4 误区四:参数顺序错误

python
# ❌ 错误:默认参数必须在位置参数后面
def func(a=1, b):
    pass    # SyntaxError

# ✅ 正确
def func(a, b=1):
    pass

七、实战案例

案例 1:BMI 计算器(函数版)

python
def calculate_bmi(height, weight):
    """计算 BMI 指数"""
    return weight / (height ** 2)

def classify_bmi(bmi):
    """根据 BMI 分类"""
    if bmi < 18.5:
        return '过轻'
    elif bmi < 25:
        return '正常'
    elif bmi < 28:
        return '过重'
    elif bmi < 32:
        return '肥胖'
    else:
        return '严重肥胖'

def main():
    height = float(input('身高(米):'))
    weight = float(input('体重(千克):'))

    bmi = calculate_bmi(height, weight)
    category = classify_bmi(bmi)

    print(f'你的 BMI:{bmi:.1f},属于:{category}')

main()

案例 2:简易记账本

python
def create_account():
    """创建账户"""
    return {'balance': 0, 'transactions': []}

def deposit(account, amount):
    """存款"""
    account['balance'] += amount
    account['transactions'].append(f'存入 {amount} 元')
    return account['balance']

def withdraw(account, amount):
    """取款"""
    if amount > account['balance']:
        return '余额不足'
    account['balance'] -= amount
    account['transactions'].append(f'取出 {amount} 元')
    return account['balance']

def print_statement(account):
    """打印账单"""
    print(f'当前余额:{account["balance"]} 元')
    print('交易记录:')
    for t in account['transactions']:
        print(f'  - {t}')

# 使用
acc = create_account()
deposit(acc, 1000)
withdraw(acc, 300)
print_statement(acc)

案例 3:密码强度检查器

python
def check_length(password):
    """检查长度"""
    return len(password) >= 8

def has_uppercase(password):
    """检查是否包含大写字母"""
    return any(c.isupper() for c in password)

def has_lowercase(password):
    """检查是否包含小写字母"""
    return any(c.islower() for c in password)

def has_digit(password):
    """检查是否包含数字"""
    return any(c.isdigit() for c in password)

def check_password_strength(password):
    """综合检查密码强度"""
    score = 0

    if check_length(password):
        score += 1
    if has_uppercase(password):
        score += 1
    if has_lowercase(password):
        score += 1
    if has_digit(password):
        score += 1

    if score == 4:
        return '强'
    elif score == 3:
        return '中'
    else:
        return '弱'

# 测试
print(check_password_strength('abc'))           # 弱
print(check_password_strength('Abc123'))        # 中
print(check_password_strength('Abc12345'))      # 强

八、动手练习

练习 1:写一个函数,计算 1 到 n 的和

python
def sum_to_n(n):
    total = 0
    for i in range(1, n + 1):
        total += i
    return total

print(sum_to_n(100))    # 5050

练习 2:写一个函数,判断一个数是否为素数

python
def is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

print(is_prime(7))     # True
print(is_prime(8))     # False

总结

概念核心要点
函数定义def 函数名(参数):
函数调用函数名(实参)
参数类型位置参数、默认参数、关键字参数、*args、**kwargs
返回值return 返回结果,无 return 返回 None
作用域局部变量只在函数内有效,全局变量用 global 声明
核心价值抽象、复用、模块化

记住:函数是你的标准配方——定义一次,调用多次。参数是输入口,返回值是输出口,抽象是核心价值


本文基于廖雪峰 Python 教程重新撰写,补充了大量背景知识、生活化类比和实战场景。推荐继续阅读:调用函数