第三单元:函数与模块

掌握函数定义与模块导入,构建模块化、可复用的代码

预计学习时间:4-5小时

单元介绍

欢迎来到Python基础课程的第三单元!在这个单元中,你将学习函数和模块的使用,这是构建大型、可维护Python程序的基础。

学习目标

  • 掌握函数的定义和调用
  • 理解函数参数的不同类型
  • 学习使用Lambda函数
  • 掌握模块的导入和使用
  • 了解Python标准库的常用模块
  • 学会创建和使用自定义模块
  • 理解包的概念和结构

学习提示

💡 重要提示:函数和模块是Python编程的核心概念,它们可以帮助你将代码组织成可复用的块,提高代码的可读性和 maintainability。建议你多做练习,加深对这些概念的理解!

3.1 函数基础:封装代码块

函数是一种将相关代码组织在一起的方式,它可以接收输入参数,执行特定的任务,并返回结果。

定义函数

在Python中,使用def关键字来定义函数:

# 定义一个简单的函数
def greet():
    print("Hello, World!")

# 调用函数
greet()

# 定义带参数的函数
def greet_name(name):
    print(f"Hello, {name}!")

# 调用带参数的函数
greet_name("John")

# 定义带返回值的函数
def add(a, b):
    return a + b

# 调用带返回值的函数
result = add(5, 3)
print(f"5 + 3 = {result}")

函数的文档字符串

文档字符串(docstring)是函数的说明文档,使用三引号包围:

def calculate_area(length, width):
    """计算矩形的面积
    
    参数:
        length (float): 矩形的长度
        width (float): 矩形的宽度
        
    返回:
        float: 矩形的面积
    """
    return length * width

# 查看函数的文档字符串
print(calculate_area.__doc__)

# 调用函数
area = calculate_area(5, 3)
print(f"面积: {area}")

函数的作用域

变量的作用域决定了它在程序中的可见性:

# 全局变量
global_var = "I'm global"

def test_scope():
    # 局部变量
    local_var = "I'm local"
    print(f"局部变量: {local_var}")
    print(f"全局变量: {global_var}")

test_scope()
print(f"全局变量: {global_var}")
# 下面的代码会报错,因为local_var是局部变量
# print(f"局部变量: {local_var}")

# 在函数中修改全局变量
def modify_global():
    global global_var
    global_var = "I'm modified"
    print(f"函数内的全局变量: {global_var}")

modify_global()
print(f"函数外的全局变量: {global_var}")

3.2 函数参数:传递数据的多种方式

Python函数支持多种类型的参数,让函数调用更加灵活。

位置参数

位置参数是最基本的参数类型,按照参数的位置进行传递:

def describe_pet(animal_type, pet_name):
    """描述宠物"""
    print(f"我有一只{animal_type}。")
    print(f"它的名字叫{pet_name}。")

# 位置参数调用
describe_pet("狗", "旺财")
describe_pet("猫", "咪咪")

关键字参数

关键字参数通过参数名来指定值,顺序可以任意:

def describe_pet(animal_type, pet_name):
    """描述宠物"""
    print(f"我有一只{animal_type}。")
    print(f"它的名字叫{pet_name}。")

# 关键字参数调用
describe_pet(animal_type="狗", pet_name="旺财")
describe_pet(pet_name="咪咪", animal_type="猫")

默认参数

默认参数为参数提供默认值,调用时可以省略:

def describe_pet(pet_name, animal_type="狗"):
    """描述宠物"""
    print(f"我有一只{animal_type}。")
    print(f"它的名字叫{pet_name}。")

# 使用默认参数
describe_pet("旺财")
# 覆盖默认参数
describe_pet("咪咪", "猫")

可变参数

可变参数允许函数接收任意数量的位置参数:

def sum_numbers(*numbers):
    """计算任意数量数字的和"""
    total = 0
    for number in numbers:
        total += number
    return total

# 调用可变参数函数
print(sum_numbers(1, 2, 3))
print(sum_numbers(1, 2, 3, 4, 5))
print(sum_numbers())

# 解包列表作为可变参数
numbers = [1, 2, 3, 4, 5]
print(sum_numbers(*numbers))

关键字可变参数

关键字可变参数允许函数接收任意数量的关键字参数:

def build_profile(first, last, **user_info):
    """构建用户信息字典"""
    profile = {}
    profile['first_name'] = first
    profile['last_name'] = last
    for key, value in user_info.items():
        profile[key] = value
    return profile

# 调用关键字可变参数函数
user_profile = build_profile('John', 'Doe', age=30, city='New York', job='Engineer')
print(user_profile)

3.3 Lambda函数:简洁的匿名函数

Lambda函数是一种小型的匿名函数,使用lambda关键字定义。

基本语法

Lambda函数的语法格式:lambda 参数: 表达式

# 定义一个简单的lambda函数
greet = lambda name: f"Hello, {name}!"

# 调用lambda函数
print(greet("John"))

# lambda函数作为参数
def apply_function(func, value):
    return func(value)

result = apply_function(lambda x: x * 2, 5)
print(result)

# 在列表排序中使用lambda
students = [
    {"name": "Alice", "grade": 90},
    {"name": "Bob", "grade": 85},
    {"name": "Charlie", "grade": 95}
]

# 按成绩排序
students.sort(key=lambda student: student["grade"])
print(students)

# 按姓名排序
students.sort(key=lambda student: student["name"])
print(students)

Lambda函数的应用场景

Lambda函数常用于需要简短函数的场景,如:

# 1. 作为内置函数的参数
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared)

# 2. 过滤列表
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers)

# 3. 作为返回值
def make_multiplier(factor):
    return lambda x: x * factor

double = make_multiplier(2)
triple = make_multiplier(3)

print(double(5))  # 10
print(triple(5))  # 15

# 4. 作为回调函数
import tkinter as tk

# 注意:在实际浏览器环境中,tkinter可能无法运行
# root = tk.Tk()
# button = tk.Button(root, text="点击我", command=lambda: print("按钮被点击了"))
# button.pack()
# root.mainloop()

3.4 模块与导入:组织代码的方式

模块是一个包含Python定义和语句的文件,文件名就是模块名加上.py后缀。

导入模块

使用import语句导入模块:

# 导入整个模块
import math

# 使用模块中的函数
print(math.sqrt(16))
print(math.pi)

# 导入模块中的特定函数
from math import sqrt, pi

print(sqrt(25))
print(pi)

# 导入模块中的所有函数
from math import *

print(cos(0))
print(sin(math.pi/2))

# 使用别名
import math as m
print(m.sqrt(36))

from math import sqrt as square_root
print(square_root(49))

模块的搜索路径

Python会按照以下顺序搜索模块:

  1. 当前目录
  2. PYTHONPATH环境变量中的目录
  3. 标准库目录
  4. 任何.pth文件中的目录
import sys
print("Python模块搜索路径:")
for path in sys.path:
    print(path)

3.5 标准库:Python的内置工具

Python标准库包含了大量有用的模块,下面介绍一些常用的标准库模块。

os模块

os模块提供了与操作系统交互的功能:

import os

# 获取当前目录
print("当前目录:", os.getcwd())

# 列出目录内容
print("目录内容:", os.listdir("."))

# 创建目录
# os.mkdir("test_dir")

# 删除目录
# os.rmdir("test_dir")

# 路径操作
print("绝对路径:", os.path.abspath("."))
print("是否是文件:", os.path.isfile("python-course.html"))
print("是否是目录:", os.path.isdir("."))
print("文件是否存在:", os.path.exists("python-course.html"))

datetime模块

datetime模块提供了处理日期和时间的功能:

import datetime

# 获取当前日期和时间
now = datetime.datetime.now()
print("当前时间:", now)

# 获取日期部分
print("日期:", now.date())

# 获取时间部分
print("时间:", now.time())

# 创建特定日期
birthday = datetime.datetime(2000, 1, 1)
print("生日:", birthday)

# 计算时间差
delta = now - birthday
print("距离生日的天数:", delta.days)

# 格式化日期
print("格式化日期:", now.strftime("%Y-%m-%d %H:%M:%S"))
print("格式化日期(中文):", now.strftime("%Y年%m月%d日 %H:%M:%S"))

random模块

random模块提供了生成随机数的功能:

import random

# 生成0-1之间的随机浮点数
print("随机浮点数:", random.random())

# 生成指定范围内的随机整数
print("随机整数(1-10):", random.randint(1, 10))

# 从序列中随机选择元素
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
print("随机水果:", random.choice(fruits))

# 打乱序列
random.shuffle(fruits)
print("打乱后的水果:", fruits)

# 生成随机样本
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print("随机样本:", random.sample(numbers, 3))

json模块

json模块提供了处理JSON数据的功能:

import json

# Python对象转JSON
person = {
    "name": "John",
    "age": 30,
    "city": "New York",
    "is_student": False
}

json_str = json.dumps(person, indent=2)
print("JSON字符串:", json_str)

# JSON转Python对象
json_str = '{"name": "Alice", "age": 25, "city": "London"}'
person = json.loads(json_str)
print("Python对象:", person)
print("姓名:", person["name"])

# 读写JSON文件
# 写入JSON文件
# with open("person.json", "w") as f:
#     json.dump(person, f, indent=2)

# 读取JSON文件
# with open("person.json", "r") as f:
#     data = json.load(f)
# print("从文件读取的数据:", data)

3.6 自定义模块:组织自己的代码

你可以创建自己的模块来组织代码,提高代码的可重用性。

创建自定义模块

创建一个名为my_module.py的文件:

# my_module.py
"""我的第一个自定义模块"""

def greet(name):
    """问候函数"""
    return f"Hello, {name}!"

def add(a, b):
    """加法函数"""
    return a + b

def multiply(a, b):
    """乘法函数"""
    return a * b

# 模块级变量
PI = 3.14159
VERSION = "1.0.0"

# 当模块被直接运行时执行
if __name__ == "__main__":
    print("这是一个模块,不是一个可执行程序")
    print(f"模块版本: {VERSION}")
    print(f"PI的值: {PI}")

使用自定义模块

在另一个文件中导入并使用自定义模块:

# 导入自定义模块
import my_module

# 使用模块中的函数
print(my_module.greet("John"))
print(my_module.add(5, 3))
print(my_module.multiply(4, 6))

# 使用模块级变量
print(f"PI: {my_module.PI}")
print(f"版本: {my_module.VERSION}")

# 导入模块中的特定函数和变量
from my_module import greet, add, VERSION

print(greet("Alice"))
print(add(10, 20))
print(f"版本: {VERSION}")

包的概念

包是一个包含多个模块的目录,必须包含一个__init__.py文件:

# 包结构示例
# my_package/
#     __init__.py
#     module1.py
#     module2.py

# __init__.py 文件
"""我的包"""

__version__ = "1.0.0"

# 导入包中的模块
from . import module1
from . import module2

# 直接导入模块中的函数
from .module1 import function1
from .module2 import function2

# 使用包
# import my_package
# print(my_package.__version__)
# print(my_package.module1.function1())
# print(my_package.function1())  # 直接从包中导入的函数

3.7 单元练习题

太棒了!你已经学完了第三单元的所有内容。现在让我们通过一些练习来巩固所学知识吧!

练习题1:函数基础

编写一个函数,计算一个数的阶乘。

查看参考答案
def factorial(n):
    """计算阶乘"""
    if n == 0 or n == 1:
        return 1
    else:
        return n * factorial(n-1)

# 测试函数
print(factorial(5))  # 120
print(factorial(10)) # 3628800

练习题2:函数参数

编写一个函数,接收任意数量的数字,返回它们的平均值。

查看参考答案
def average(*numbers):
    """计算任意数量数字的平均值"""
    if not numbers:
        return 0
    return sum(numbers) / len(numbers)

# 测试函数
print(average(1, 2, 3, 4, 5))  # 3.0
print(average(10, 20, 30))     # 20.0
print(average())                 # 0

练习题3:Lambda函数

使用Lambda函数对列表中的元素进行排序,按照字符串长度排序。

查看参考答案
words = ["apple", "banana", "cherry", "date", "elderberry"]

# 使用Lambda函数按照字符串长度排序
words.sort(key=lambda word: len(word))
print(words)

# 使用Lambda函数按照字符串长度降序排序
words.sort(key=lambda word: len(word), reverse=True)
print(words)

练习题4:模块使用

使用标准库模块,生成一个包含10个随机整数的列表,并计算它们的和与平均值。

查看参考答案
import random

# 生成10个1-100之间的随机整数
numbers = [random.randint(1, 100) for _ in range(10)]
print("随机数列表:", numbers)

# 计算和
total = sum(numbers)
print("总和:", total)

# 计算平均值
average = total / len(numbers)
print("平均值:", average)

练习题5:自定义模块

创建一个自定义模块,包含计算圆面积和周长的函数,然后在另一个文件中使用它。

查看参考答案
# circle.py
"""圆相关的计算模块"""

PI = 3.14159

def area(radius):
    """计算圆的面积"""
    return PI * radius ** 2

def circumference(radius):
    """计算圆的周长"""
    return 2 * PI * radius

# 使用模块
# import circle
# 
# r = 5
# print(f"半径为{r}的圆的面积: {circle.area(r)}")
# print(f"半径为{r}的圆的周长: {circle.circumference(r)}")

单元总结

🎉 恭喜你完成了第三单元的学习!

  • 你掌握了函数的定义和调用
  • 你理解了不同类型的函数参数
  • 你学会了使用Lambda函数
  • 你掌握了模块的导入和使用
  • 你了解了Python标准库的常用模块
  • 你学会了创建和使用自定义模块
  • 你理解了包的概念和结构

继续加油,下一个单元我们将学习面向对象编程!