Skip to content

Python基础语法与数据类型:编程世界的基石与积木

数据类型是编程的基石,理解它们就像建筑师了解材料特性一样重要。掌握基础语法,你就能用Python搭建任何你想象的数字世界。

前言:从"Hello World"到真正的编程

还记得上一章我们写的print("Hello World")吗?这就像是站在编程世界的门口打了声招呼。现在,我们要真正走进这个世界,学习它的基本规则和构造材料。

编程的本质是什么? 很多人可能会说是"写代码",但实际上,编程是用计算机能理解的方式描述问题和解决方案。而Python的数据类型和基础语法,就是我们描述世界的"词汇表"和"语法规则"。

让我用一个简单的比喻来解释:如果把编程比作建造一座大厦,那么:

  • 变量是给建筑材料起的名字
  • 数据类型是建筑材料的种类(砖头、水泥、钢筋)
  • 运算符是连接材料的方法(砌墙、浇筑)
  • 注释是建筑图纸上的说明文字

在这一章,我们将一起探索Python世界的这些基础构件,为后续更复杂的编程打下坚实的基础。

3.1 变量与赋值:给数据起个好名字

什么是变量?

想象一下你去超市购物。你不会对收银员说:"请把我刚才从第三排货架拿的那个蓝色包装、重量500克的东西结账",而是会说:"请把这包薯片结账"。这里的"薯片"就是一个变量名,它代表了一包具体的薯片。

在Python中,变量就是数据的名字。通过这个名字,我们可以引用和操作数据。

python
# 变量赋值的基本语法
商品名称 = "薯片"          # 字符串类型变量
商品价格 = 8.5            # 浮点数类型变量
商品数量 = 3              # 整数类型变量

# 使用变量进行计算
总价 = 商品价格 * 商品数量
print(f"您购买了{商品数量}{商品名称},总价为{总价}元")
# 输出:您购买了3包薯片,总价为25.5元

Python变量的特点

1. 动态类型:变量类型可以随时改变

python
# 同一个变量名可以存储不同类型的数据
x = 100            # x是整数
print(f"x的类型是: {type(x)}, 值是: {x}")  # <class 'int'>, 100

x = "一百"          # x现在是字符串
print(f"x的类型是: {type(x)}, 值是: {x}")  # <class 'str'>, 一百

x = 100.0          # x现在是浮点数
print(f"x的类型是: {type(x)}, 值是: {x}")  # <class 'float'>, 100.0

2. 引用语义:变量是数据的"标签"

python
# 理解Python的引用机制
a = [1, 2, 3]  # a指向一个列表
b = a          # b也指向同一个列表
b.append(4)    # 通过b修改列表

print(a)  # 输出: [1, 2, 3, 4] - a也被修改了!
print(b)  # 输出: [1, 2, 3, 4]

# 验证a和b指向同一个对象
print(f"a的id: {id(a)}")  # 输出内存地址
print(f"b的id: {id(b)}")  # 相同的内存地址
print(f"a is b: {a is b}")  # 输出: True

3. 命名规则与最佳实践

python
# 有效的变量名
username = "张三"
user_age = 25
is_student = True
MAX_COUNT = 100  # 常量通常用全大写

# 无效的变量名(会引发错误)
# 123abc = 10        # 不能以数字开头
# user-name = "李四"  # 不能包含连字符
# class = "Python"   # 不能使用关键字

# Python关键字列表
import keyword
print("Python关键字:")
print(keyword.kwlist)
# 输出: ['False', 'None', 'True', 'and', 'as', 'assert', ...]

# 变量命名最佳实践
def 计算用户折扣(用户等级, 消费金额):
    """
    计算用户折扣 - 使用有意义的变量名

    参数:
        用户等级: str, 用户等级(如 'VIP', '普通')
        消费金额: float, 消费金额

    返回:
        float: 折扣后的金额
    """
    # 定义折扣率字典
    折扣率表 = {
        'VIP': 0.8,      # 8折
        '高级': 0.85,     # 85折
        '普通': 0.9,      # 9折
        '新用户': 0.95    # 95折
    }

    # 获取折扣率,默认为1(无折扣)
    折扣率 = 折扣率表.get(用户等级, 1.0)

    # 计算折扣后金额
    折扣后金额 = 消费金额 * 折扣率

    # 返回结果,保留两位小数
    return round(折扣后金额, 2)

# 使用函数
用户A = "VIP"
消费A = 1000.0
结果A = 计算用户折扣(用户A, 消费A)
print(f"{用户A}用户消费{消费A}元,折扣后需支付{结果A}元")
# 输出: VIP用户消费1000.0元,折扣后需支付800.0元

多重赋值与交换技巧

python
# 传统方式交换两个变量的值
a = 10
b = 20
print(f"交换前: a={a}, b={b}")

temp = a  # 需要临时变量
a = b
b = temp
print(f"交换后: a={a}, b={b}")

# Python的优雅方式
a, b = 10, 20
print(f"交换前: a={a}, b={b}")
a, b = b, a  # 一行搞定交换!
print(f"交换后: a={a}, b={b}")

# 多重赋值
x, y, z = 1, 2, 3  # 同时给多个变量赋值
print(f"x={x}, y={y}, z={z}")

# 使用*收集多余的值
first, *middle, last = [1, 2, 3, 4, 5, 6]
print(f"first={first}")    # 1
print(f"middle={middle}")  # [2, 3, 4, 5]
print(f"last={last}")      # 6

# 变量交换的实际应用:排序算法中的一部分
def 简单排序(列表):
    """演示变量交换在排序中的应用"""
    n = len(列表)
    for i in range(n):
        for j in range(i + 1, n):
            if 列表[j] < 列表[i]:  # 如果后面的元素更小
                列表[i], 列表[j] = 列表[j], 列表[i]  # 交换位置
    return 列表

测试列表 = [64, 34, 25, 12, 22, 11, 90]
print(f"排序前: {测试列表}")
print(f"排序后: {简单排序(测试列表.copy())}")

3.2 基本数据类型:整数、浮点数、字符串

整数(int):精确的计数

整数是编程中最基础的数据类型,用于表示没有小数部分的数字。

python
# 整数的各种表示形式
十进制 = 100
print(f"十进制 100: {十进制}")

二进制 = 0b1100100  # 0b开头表示二进制
print(f"二进制 0b1100100: {二进制}")

八进制 = 0o144  # 0o开头表示八进制
print(f"八进制 0o144: {八进制}")

十六进制 = 0x64  # 0x开头表示十六进制
print(f"十六进制 0x64: {十六进制}")

# 大整数支持(Python可以处理非常大的整数)
大数 = 10**100  # 10的100次方
print(f"大整数 10^100 有 {len(str(大数))} 位数字")

# 整数运算
a = 17
b = 5

print(f"{a} + {b} = {a + b}")  # 加法
print(f"{a} - {b} = {a - b}")  # 减法
print(f"{a} * {b} = {a * b}")  # 乘法
print(f"{a} / {b} = {a / b}")  # 除法(返回浮点数)
print(f"{a} // {b} = {a // b}")  # 整除(向下取整)
print(f"{a} % {b} = {a % b}")  # 取余
print(f"{a} ** {b} = {a ** b}")  # 幂运算

浮点数(float):带小数的实数

浮点数用于表示实数(带小数点的数字),但在计算机中是以近似值存储的。

python
# 浮点数的表示
pi = 3.141592653589793
print(f"π: {pi}")

# 科学计数法
地球质量 = 5.972e24  # 5.972 × 10^24 千克
电子质量 = 9.109e-31  # 9.109 × 10^-31 千克
print(f"地球质量: {地球质量} 千克")
print(f"电子质量: {电子质量} 千克")

# 浮点数精度问题(重要!)
print(f"0.1 + 0.2 = {0.1 + 0.2}")  # 输出: 0.30000000000000004

# 为什么?计算机用二进制表示小数,有些十进制小数无法精确表示
# 解决方案:使用Decimal模块进行精确计算
from decimal import Decimal
print(f"Decimal('0.1') + Decimal('0.2') = {Decimal('0.1') + Decimal('0.2')}")

# 或者使用round函数四舍五入
print(f"round(0.1 + 0.2, 2) = {round(0.1 + 0.2, 2)}")

# 浮点数比较的正确方式
def 浮点数相等(a, b, 精度=1e-9):
    """比较两个浮点数是否在指定精度内相等"""
    return abs(a - b) < 精度

a = 0.1 + 0.2
b = 0.3
print(f"直接比较: {a == b}")  # False
print(f"精度比较: {浮点数相等(a, b)}")  # True

字符串(str):文本的容器

字符串是Python中用于表示文本的数据类型,功能极其强大。

python
# 字符串的多种创建方式
字符串1 = '单引号字符串'
字符串2 = "双引号字符串"
字符串3 = '''三引号可以
跨越多行
的字符串'''
字符串4 = """这也是
多行字符串"""

print(字符串1)
print(字符串2)
print(字符串3)
print(字符串4)

# 字符串索引和切片
文本 = "Python编程很有趣!"
print(f"完整文本: {文本}")
print(f"长度: {len(文本)}")  # 字符串长度
print(f"第一个字符: {文本[0]}")  # P
print(f"最后一个字符: {文本[-1]}")  # !
print(f"前6个字符: {文本[:6]}")  # Python
print(f"第7到第9个字符: {文本[6:9]}")  # 编程很
print(f"每隔一个字符: {文本[::2]}")  # Pto编很趣
print(f"反转字符串: {文本[::-1]}")  # !趣很有程编nohtyP

# 字符串常用方法
示例文本 = "  Python是很好的编程语言,Python简单易学!  "

print(f"原始文本: '{示例文本}'")
print(f"去除空格: '{示例文本.strip()}'")
print(f"转为大写: '{示例文本.upper()}'")
print(f"转为小写: '{示例文本.lower()}'")
print(f"替换Python为Java: '{示例文本.replace('Python', 'Java')}'")
print(f"查找'编程'的位置: {示例文本.find('编程')}")
print(f"'Python'出现次数: {示例文本.count('Python')}")
print(f"是否以'  Python'开头: {示例文本.startswith('  Python')}")
print(f"是否以'!  '结尾: {示例文本.endswith('!  ')}")

# 字符串分割与连接
csv数据 = "张三,25,男,北京"
字段列表 = csv数据.split(',')
print(f"CSV数据: {csv数据}")
print(f"分割后: {字段列表}")

# 连接字符串
新字符串 = '-'.join(字段列表)
print(f"用'-'连接: {新字符串}")

# f-string(格式化字符串字面量)- Python 3.6+ 推荐使用
姓名 = "张三"
年龄 = 25
身高 = 1.75
体重 = 70

# 传统格式化方式
print("姓名: %s, 年龄: %d" % (姓名, 年龄))
print("姓名: {}, 年龄: {}".format(姓名, 年龄))

# f-string方式(最简洁)
print(f"姓名: {姓名}, 年龄: {年龄}")
print(f"BMI指数: {体重 / (身高 ** 2):.2f}")  # 保留两位小数
print(f"明年年龄: {年龄 + 1}")
print(f"姓名长度: {len(姓名)}")

# 多行f-string
信息 = f"""
个人信息报告
============
姓名: {姓名}
年龄: {年龄}
身高: {身高}
体重: {体重}公斤
BMI: {体重 / (身高 ** 2):.1f}
状态: {'正常' if 18.5 <= 体重 / (身高 ** 2) < 24 else '注意'}
"""
print(信息)

3.3 数据类型转换:在不同类型间架起桥梁

显式类型转换

Python提供了内置函数来进行显式的类型转换。

python
# 整数与浮点数之间的转换
整数 = 100
浮点数 = 3.14

# 整数转浮点数
整数转浮点 = float(整数)
print(f"int({整数}) -> float: {整数转浮点}, 类型: {type(整数转浮点)}")

# 浮点数转整数(会丢失小数部分)
浮点转整数 = int(浮点数)
print(f"float({浮点数}) -> int: {浮点转整数}, 类型: {type(浮点转整数)}")

# 注意:int()会直接截断小数,不是四舍五入
print(f"int(3.99) = {int(3.99)}")  # 输出: 3

# 如果需要四舍五入,使用round()
print(f"round(3.99) = {round(3.99)}")  # 输出: 4

# 字符串与数字之间的转换
数字字符串 = "123"
浮点字符串 = "3.14"

# 字符串转整数
字符串转整数 = int(数字字符串)
print(f"str('{数字字符串}') -> int: {字符串转整数}")

# 字符串转浮点数
字符串转浮点 = float(浮点字符串)
print(f"str('{浮点字符串}') -> float: {字符串转浮点}")

# 数字转字符串
数字转字符串 = str(整数)
print(f"int({整数}) -> str: '{数字转字符串}', 类型: {type(数字转字符串)}")

# 布尔类型转换
print(f"bool(0) = {bool(0)}")        # False
print(f"bool(1) = {bool(1)}")        # True
print(f"bool(-1) = {bool(-1)}")      # True(非零数字都为True)
print(f"bool('') = {bool('')}")      # False(空字符串)
print(f"bool('Python') = {bool('Python')}")  # True(非空字符串)
print(f"bool([]) = {bool([])}")      # False(空列表)
print(f"bool([1,2]) = {bool([1,2])}") # True(非空列表)

隐式类型转换

Python在某些情况下会自动进行类型转换,这称为隐式类型转换或类型强制转换。

python
# 整数和浮点数运算时的隐式转换
整数 = 10
浮点数 = 3.5

结果 = 整数 + 浮点数  # 整数被隐式转换为浮点数
print(f"{整数} + {浮点数} = {结果}, 类型: {type(结果)}")

# 布尔值参与算术运算时的隐式转换
print(f"True + 5 = {True + 5}")   # True被转换为1,输出6
print(f"False * 10 = {False * 10}")  # False被转换为0,输出0

# 在实际编程中的应用
def 计算平均分(分数列表):
    """计算平均分,演示隐式类型转换"""
    if not 分数列表:  # 空列表隐式转换为False
        return 0

    总分 = sum(分数列表)  # sum()函数返回整数或浮点数
    人数 = len(分数列表)  # len()函数返回整数

    return 总分 / 人数  # 整数除以整数可能得到浮点数

分数 = [85, 92, 78, 90, 88]
平均分 = 计算平均分(分数)
print(f"分数: {分数}")
print(f"平均分: {平均分:.2f}")  # 86.60

类型转换的实际应用

python
# 应用1:用户输入处理
def 计算圆面积():
    """接收用户输入的半径,计算圆面积"""
    while True:
        输入 = input("请输入圆的半径(输入q退出): ")

        if 输入.lower() == 'q':
            print("程序结束")
            break

        try:
            半径 = float(输入)  # 尝试将输入转换为浮点数
            if 半径 <= 0:
                print("半径必须大于0!")
                continue

            面积 = 3.14159 * 半径 ** 2
            周长 = 2 * 3.14159 * 半径

            print(f"半径为 {半径} 的圆:")
            print(f"  面积 = {面积:.2f}")
            print(f"  周长 = {周长:.2f}")

        except ValueError:
            print("输入错误,请输入数字!")

# 运行示例(注释掉实际运行,只展示代码)
# 计算圆面积()

# 应用2:数据清洗与验证
def 清洗用户数据(原始数据):
    """
    清洗用户输入的数值数据

    参数:
        原始数据: list, 可能包含各种类型的元素

    返回:
        list: 只包含数值的列表
    """
    清洗后数据 = []

    for 项目 in 原始数据:
        # 尝试将项目转换为数值
        try:
            if isinstance(项目, str):
                # 如果是字符串,尝试转换为浮点数
                数值 = float(项目)
            else:
                # 如果不是字符串,尝试直接转换
                数值 = float(项目)

            # 检查是否为有效数值(不是无穷大或NaN)
            if 数值 != 数值:  # NaN不等于自身
                continue
            if abs(数值) == float('inf'):
                continue

            清洗后数据.append(数值)

        except (ValueError, TypeError):
            # 转换失败,跳过此项
            continue

    return 清洗后数据

# 测试数据清洗
测试数据 = ["123", 456, "78.9", "abc", None, "100", float('nan'), float('inf')]
清洗结果 = 清洗用户数据(测试数据)
print(f"原始数据: {测试数据}")
print(f"清洗后数据: {清洗结果}")

# 应用3:生成格式化的报告
def 生成成绩报告(学生数据):
    """
    根据学生数据生成格式化的成绩报告
    """
    报告 = []
    报告.append("=" * 40)
    报告.append("学生成绩报告")
    报告.append("=" * 40)

    总分 = 0
    最高分 = -float('inf')
    最低分 = float('inf')

    for 学号, 成绩 in 学生数据.items():
        成绩数值 = float(成绩)  # 确保成绩是数值

        总分 += 成绩数值
        最高分 = max(最高分, 成绩数值)
        最低分 = min(最低分, 成绩数值)

        报告.append(f"学号 {学号:4s}: {成绩数值:6.2f} 分")

    平均分 = 总分 / len(学生数据) if 学生数据 else 0

    报告.append("-" * 40)
    报告.append(f"平均分: {平均分:8.2f} 分")
    报告.append(f"最高分: {最高分:8.2f} 分")
    报告.append(f"最低分: {最低分:8.2f} 分")
    报告.append("=" * 40)

    return "\n".join(报告)

# 测试生成报告
学生成绩 = {
    "001": "85.5",
    "002": 92.0,
    "003": "78.5",
    "004": "88.0",
    "005": 95.5
}

print(生成成绩报告(学生成绩))

3.4 注释与代码风格:写出人类也能读懂的代码

注释的艺术

注释是写给人类看的代码说明,好的注释能让代码更易理解和维护。

python
# 单行注释:解释下面这行代码的作用
# 计算圆的面积
半径 = 5
面积 = 3.14159 * 半径 ** 2

"""
多行注释(文档字符串)
可以跨越多行,通常用于函数、类或模块的说明
这是计算圆面积的示例
"""

def 计算面积(半径):
    """
    计算圆的面积

    参数:
        半径 (float): 圆的半径,必须大于0

    返回:
        float: 圆的面积

    示例:
        >>> 计算面积(5)
        78.53975

    注意:
        如果半径小于等于0,将返回0
    """
    if 半径 <= 0:
        return 0
    return 3.14159 * 半径 ** 2


# 内联注释:解释复杂的表达式
# 计算BMI指数,保留两位小数
体重 = 70  # 单位:公斤
身高 = 1.75  # 单位:米
bmi = 体重 / (身高 ** 2)  # BMI = 体重(kg) / 身高(m)^2

# TODO注释:标记需要完成的工作
# TODO: 添加对负数半径的处理
# FIXME: 这里的算法效率需要优化
# HACK: 临时解决方案,需要重构
# NOTE: 重要提醒,这个函数会在v2.0中弃用

# 魔法注释:影响解释器行为的特殊注释
# -*- coding: utf-8 -*-  # 指定文件编码为UTF-8

#!/usr/bin/env python3  # Shebang行,指定脚本解释器(Unix-like系统)

# type: ignore  # 告诉类型检查器忽略这一行

Python代码风格指南(PEP 8)

PEP 8是Python官方的代码风格指南,遵循它能让你的代码更专业、更易读。

python
"""
PEP 8代码风格示例
"""

# 1. 缩进:使用4个空格(不要用Tab)
def 示例函数():
    """正确:使用4个空格缩进"""
    if True:
        print("缩进正确")


# 2. 行长:每行不超过79个字符(文档字符串不超过72)
# 对于过长的行,可以使用括号、反斜杠或换行符来分行
长字符串 = (
    "这是一个非常长的字符串,我们需要"
    "将它分成多行来保持代码的可读性"
)

# 函数调用分行
结果 = 复杂函数(
    参数1=值1,
    参数2=值2,
    参数3=值3,
    参数4=值4
)

# 3. 空行:合理使用空行分隔代码块
# 导入语句后
import os
import sys

# 函数定义之间
def 函数1():
    pass


def 函数2():
    pass


# 类方法之间
class 示例类:
    def 方法1(self):
        pass

    def 方法2(self):
        pass


# 4. 导入顺序:分组并按字母顺序排列
# 标准库导入
import json
import os
import sys
from datetime import datetime

# 第三方库导入
import numpy as np
import pandas as pd

# 本地应用/库导入
from . import 本地模块
from .子包 import 子模块


# 5. 命名约定
# 变量和函数:小写字母,单词间用下划线分隔
变量名 = "value"
函数名 = "calculate_value"

# 常量:全大写字母,单词间用下划线分隔
MAX_SIZE = 100
DEFAULT_TIMEOUT = 30

# 类名:首字母大写的驼峰命名法
class 用户类:
    pass


class 数据处理器:
    pass


# 6. 避免使用无关的变量名
# 不好
x = 获取数据()
y = 处理数据(x)

# 好
原始数据 = 获取数据()
处理后的数据 = 处理数据(原始数据)


# 7. 表达式和语句中的空格
# 正确:运算符周围有空格
x = 1 + 2
if x == 3:
    print(x)

# 错误:运算符周围没有空格或空格不一致
y=1+2
if y==3:
    print(y)

# 函数调用时不加空格
print("Hello")  # 正确
print ("Hello")  # 错误


# 8. 文档字符串(docstring)规范
class 学生:
    """学生类,表示一个学生对象

    属性:
        姓名 (str): 学生姓名
        年龄 (int): 学生年龄
        成绩 (dict): 各科成绩

    方法:
        计算平均分: 计算学生的平均成绩
        获取信息: 返回学生的基本信息
    """

    def __init__(self, 姓名, 年龄, 成绩=None):
        """初始化学生对象

        参数:
            姓名: 学生姓名
            年龄: 学生年龄
            成绩: 可选,学生成绩字典
        """
        self.姓名 = 姓名
        self.年龄 = 年龄
        self.成绩 = 成绩 if 成绩 is not None else {}

    def 计算平均分(self):
        """计算学生的平均成绩

        返回:
            float: 平均分,保留两位小数

        异常:
            ValueError: 当没有成绩时

        示例:
            >>> 学生 = 学生("张三", 18, {"数学": 90, "语文": 85})
            >>> 学生.计算平均分()
            87.5
        """
        if not self.成绩:
            raise ValueError("该学生没有成绩记录")

        总分 = sum(self.成绩.values())
        科目数 = len(self.成绩)

        return round(总分 / 科目数, 2)

    def 获取信息(self):
        """返回学生的基本信息

        返回:
            str: 格式化的学生信息
        """
        return f"姓名: {self.姓名}, 年龄: {self.年龄}, 科目数: {len(self.成绩)}"

代码格式化工具

python
"""
使用工具自动格式化代码
"""

# 安装代码格式化工具
# pip install black flake8 isort

# black:自动格式化代码
# 使用:black 文件名.py

# flake8:代码风格检查
# 使用:flake8 文件名.py

# isort:自动排序import语句
# 使用:isort 文件名.py

# 示例:不符合PEP 8的代码
def 不好的代码():
    x=1
    y=2
    z=3
    if x==y:
        print("相等")
    else:
        print("不相等")
    return x+y+z

# 使用black格式化后:
def 好的代码():
    x = 1
    y = 2
    z = 3
    if x == y:
        print("相等")
    else:
        print("不相等")
    return x + y + z


# 创建配置文件统一代码风格
# .flake8 文件内容:
"""
[flake8]
max-line-length = 88
extend-ignore = E203
"""

# pyproject.toml 文件内容(black配置):
"""
[tool.black]
line-length = 88
target-version = ['py38']
include = '\.pyi?$'
exclude = '''
/(
    \.eggs
  | \.git
  | \.hg
  | \.mypy_cache
  | \.tox
  | \.venv
  | _build
  | buck-out
  | build
  | dist
)/
'''
"""

3.5 运算符:算术、比较、逻辑

算术运算符

python
# 基本算术运算符
a = 10
b = 3

print(f"{a} + {b} = {a + b}")   # 加法:13
print(f"{a} - {b} = {a - b}")   # 减法:7
print(f"{a} * {b} = {a * b}")   # 乘法:30
print(f"{a} / {b} = {a / b}")   # 除法:3.333...
print(f"{a} // {b} = {a // b}") # 整除:3
print(f"{a} % {b} = {a % b}")   # 取余:1
print(f"{a} ** {b} = {a ** b}") # 幂运算:1000

# 赋值运算符
x = 5
print(f"初始值: x = {x}")

x += 3  # 等价于 x = x + 3
print(f"x += 3 后: x = {x}")

x -= 2  # 等价于 x = x - 2
print(f"x -= 2 后: x = {x}")

x *= 2  # 等价于 x = x * 2
print(f"x *= 2 后: x = {x}")

x /= 4  # 等价于 x = x / 4
print(f"x /= 4 后: x = {x}")

x //= 2  # 等价于 x = x // 2
print(f"x //= 2 后: x = {x}")

x %= 3  # 等价于 x = x % 3
print(f"x %= 3 后: x = {x}")

x **= 3  # 等价于 x = x ** 3
print(f"x **= 3 后: x = {x}")

# 算术运算符的实际应用
def 计算购物车总价(商品列表, 折扣=0, 运费=0):
    """计算购物车总价,考虑折扣和运费"""
    商品总价 = sum(商品列表)

    # 应用折扣
    if 折扣 > 0:
        折扣金额 = 商品总价 * (折扣 / 100)
        折扣后价格 = 商品总价 - 折扣金额
    else:
        折扣后价格 = 商品总价

    # 添加运费
    最终价格 = 折扣后价格 + 运费

    return 最终价格

# 测试
商品价格 = [25.5, 39.9, 15.0, 42.8]
总价 = 计算购物车总价(商品价格, 折扣=10, 运费=8)
print(f"商品价格: {商品价格}")
print(f"折扣10%,运费8元,总价: {总价:.2f}元")

比较运算符

python
# 基本比较运算符
a = 10
b = 20

print(f"{a} == {b}: {a == b}")  # 等于:False
print(f"{a} != {b}: {a != b}")  # 不等于:True
print(f"{a} > {b}: {a > b}")    # 大于:False
print(f"{a} < {b}: {a < b}")    # 小于:True
print(f"{a} >= {b}: {a >= b}")  # 大于等于:False
print(f"{a} <= {b}: {a <= b}")  # 小于等于:True

# 字符串比较(按字典序)
print(f"'apple' < 'banana': {'apple' < 'banana'}")  # True
print(f"'apple' == 'Apple': {'apple' == 'Apple'}")  # False(区分大小写)

# 列表比较
print(f"[1, 2, 3] == [1, 2, 3]: {[1, 2, 3] == [1, 2, 3]}")  # True
print(f"[1, 2, 3] != [3, 2, 1]: {[1, 2, 3] != [3, 2, 1]}")  # True

# 链式比较
x = 5
print(f"0 < {x} < 10: {0 < x < 10}")  # True
print(f"0 < {x} <= 5: {0 < x <= 5}")  # True

# 比较运算符的实际应用
def 判断成绩等级(分数):
    """根据分数判断成绩等级"""
    if 分数 >= 90:
        return "A"
    elif 分数 >= 80:  # 80 <= 分数 < 90
        return "B"
    elif 分数 >= 70:
        return "C"
    elif 分数 >= 60:
        return "D"
    else:
        return "F"

def 验证用户输入(用户名, 密码):
    """验证用户输入是否符合要求"""
    错误信息 = []

    # 检查用户名长度
    if len(用户名) < 3:
        错误信息.append("用户名至少3个字符")
    elif len(用户名) > 20:
        错误信息.append("用户名最多20个字符")

    # 检查密码长度和复杂度
    if len(密码) < 6:
        错误信息.append("密码至少6个字符")
    elif len(密码) > 30:
        错误信息.append("密码最多30个字符")

    # 检查密码是否包含数字
    if not any(c.isdigit() for c in 密码):
        错误信息.append("密码必须包含至少一个数字")

    # 检查密码是否包含字母
    if not any(c.isalpha() for c in 密码):
        错误信息.append("密码必须包含至少一个字母")

    return 错误信息

# 测试
测试分数 = [95, 85, 75, 65, 55]
print("成绩等级测试:")
for 分数 in 测试分数:
    print(f"  分数{分数}: {判断成绩等级(分数)}等级")

print("\n用户输入验证测试:")
测试用户 = [("ab", "123"), ("用户名太长超过20个字符", "简单密码"), ("正常用户", "Pass123")]
for 用户名, 密码 in 测试用户:
    错误 = 验证用户输入(用户名, 密码)
    if 错误:
        print(f"  '{用户名}' 错误: {', '.join(错误)}")
    else:
        print(f"  '{用户名}' 验证通过")

逻辑运算符

python
# 基本逻辑运算符
# and: 与,两个条件都为True时返回True
# or: 或,至少一个条件为True时返回True
# not: 非,取反

a = True
b = False

print(f"{a} and {b}: {a and b}")  # False
print(f"{a} or {b}: {a or b}")    # True
print(f"not {a}: {not a}")        # False
print(f"not {b}: {not b}")        # True

# 短路求值特性
def 返回True():
    print("返回True函数被调用")
    return True

def 返回False():
    print("返回False函数被调用")
    return False

print("\n短路求值演示:")
print("False and 返回True():")
结果1 = 返回False() and 返回True()  # 只调用返回False函数

print("\nTrue or 返回False():")
结果2 = 返回True() or 返回False()   # 只调用返回True函数

# 逻辑运算符的实际应用
def 判断闰年(年份):
    """判断是否为闰年"""
    # 闰年规则:
    # 1. 能被4整除但不能被100整除,或者
    # 2. 能被400整除
    return (年份 % 4 == 0 and 年份 % 100 != 0) or (年份 % 400 == 0)

def 检查用户权限(用户, 操作, 资源):
    """检查用户是否有权限执行操作"""
    # 模拟用户权限检查
    用户角色 = 用户.get("角色", "访客")
    用户权限 = 用户.get("权限", [])

    # 检查条件:
    # 1. 用户是管理员,或者
    # 2. 用户是资源所有者,或者
    # 3. 操作在用户权限列表中
    是管理员 = 用户角色 == "管理员"
    是所有者 = 用户.get("用户名") == 资源.get("所有者")
    有权限 = 操作 in 用户权限

    return 是管理员 or 是所有者 or 有权限

# 测试闰年判断
测试年份 = [2000, 2004, 1900, 2020, 2021]
print("\n闰年判断:")
for 年份 in 测试年份:
    print(f"  年份{年份}: {'是' if 判断闰年(年份) else '不是'}闰年")

# 测试权限检查
print("\n用户权限检查:")
用户A = {"用户名": "张三", "角色": "普通用户", "权限": ["读取", "编辑"]}
用户B = {"用户名": "李四", "角色": "管理员", "权限": []}
资源1 = {"名称": "文档1", "所有者": "张三"}

测试用例 = [
    (用户A, "读取", 资源1),
    (用户A, "删除", 资源1),
    (用户B, "删除", 资源1),
]

for 用户, 操作, 资源 in 测试用例:
    有权限 = 检查用户权限(用户, 操作, 资源)
    print(f"  用户{用户['用户名']} {操作} {资源['名称']}: {'允许' if 有权限 else '拒绝'}")

身份运算符和成员运算符

python
# 身份运算符:is, is not
# 比较两个对象是否是同一个对象(内存地址相同)

a = [1, 2, 3]
b = a          # b引用同一个列表
c = [1, 2, 3]  # c创建了新的列表

print(f"a is b: {a is b}")      # True,同一个对象
print(f"a is c: {a is c}")      # False,不同对象
print(f"a == c: {a == c}")      # True,值相同

# 小整数缓存(-5到256)
x = 100
y = 100
print(f"\n小整数缓存测试:")
print(f"x = 100, y = 100")
print(f"x is y: {x is y}")      # True,Python会缓存小整数

x = 1000
y = 1000
print(f"\nx = 1000, y = 1000")
print(f"x is y: {x is y}")      # 可能True也可能False,取决于实现

# 成员运算符:in, not in
# 检查一个元素是否在容器中

列表 = [1, 2, 3, 4, 5]
字符串 = "Hello, Python!"
字典 = {"a": 1, "b": 2, "c": 3}

print(f"\n成员运算符测试:")
print(f"3 in {列表}: {3 in 列表}")              # True
print(f"6 not in {列表}: {6 not in 列表}")      # True
print(f"'Python' in '{字符串}': {'Python' in 字符串}")  # True
print(f"'a' in {字典}: {'a' in 字典}")          # True(检查键)
print(f"1 in {字典}.values(): {1 in 字典.values()}")  # True(检查值)

# 实际应用:数据验证
def 验证邮箱格式(邮箱):
    """验证邮箱格式是否正确"""
    if "@" not in 邮箱:
        return False, "邮箱必须包含@符号"

    用户名, 域名 = 邮箱.split("@", 1)

    if not 用户名:
        return False, "用户名不能为空"

    if "." not in 域名:
        return False, "域名必须包含点号"

    if len(域名.split(".")[-1]) < 2:
        return False, "顶级域名至少2个字符"

    return True, "邮箱格式正确"

# 测试邮箱验证
测试邮箱 = ["user@example.com", "user@com", "@example.com", "user@example.c"]
print("\n邮箱验证测试:")
for 邮箱 in 测试邮箱:
    有效, 信息 = 验证邮箱格式(邮箱)
    print(f"  {邮箱}: {信息}")

3.6 复合数据类型:列表、元组

列表(list):灵活有序的集合

列表是Python中最常用、最灵活的数据结构之一,可以存储任意类型的元素,并且可以动态调整大小。

python
# 列表的创建
空列表 = []
数字列表 = [1, 2, 3, 4, 5]
混合列表 = [1, "two", 3.0, True, [5, 6]]
生成列表 = list("Python")  # ['P', 'y', 't', 'h', 'o', 'n']
范围列表 = list(range(1, 11))  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

print(f"空列表: {空列表}")
print(f"数字列表: {数字列表}")
print(f"混合列表: {混合列表}")
print(f"生成列表: {生成列表}")
print(f"范围列表: {范围列表}")

# 列表基本操作
列表 = [10, 20, 30, 40, 50]

# 访问元素
print(f"\n列表: {列表}")
print(f"第一个元素: {列表[0]}")
print(f"最后一个元素: {列表[-1]}")
print(f"第二个到第四个元素: {列表[1:4]}")
print(f"每隔一个元素: {列表[::2]}")

# 修改元素
列表[0] = 100
列表[-1] = 500
print(f"修改后列表: {列表}")

# 添加元素
列表.append(600)  # 末尾添加
列表.insert(2, 250)  # 在索引2处插入
print(f"添加后列表: {列表}")

# 删除元素
删除的值 = 列表.pop()  # 删除并返回最后一个元素
print(f"pop()删除: {删除的值}, 列表: {列表}")

删除的值 = 列表.pop(2)  # 删除索引2处的元素
print(f"pop(2)删除: {删除的值}, 列表: {列表}")

列表.remove(100)  # 删除第一个值为100的元素
print(f"remove(100)后列表: {列表}")

del 列表[1:3]  # 删除索引1到3(不包括3)的元素
print(f"del后列表: {列表}")

# 列表常用方法
列表 = [3, 1, 4, 1, 5, 9, 2, 6]

print(f"\n原始列表: {列表}")
print(f"长度: {len(列表)}")
print(f"最大值: {max(列表)}")
print(f"最小值: {min(列表)}")
print(f"总和: {sum(列表)}")

# 排序
列表.sort()  # 原地排序
print(f"排序后: {列表}")

列表.sort(reverse=True)  # 降序排序
print(f"降序排序: {列表}")

排序副本 = sorted(列表)  # 返回新列表
print(f"排序副本: {排序副本}")
print(f"原列表不变: {列表}")

# 反转
列表.reverse()
print(f"反转后: {列表}")

# 查找
print(f"元素5的索引: {列表.index(5)}")  # 首次出现的位置
print(f"元素1出现的次数: {列表.count(1)}")

# 列表推导式(强大而简洁的创建列表方式)
# 基本语法:[表达式 for 变量 in 可迭代对象 if 条件]

# 创建平方数列表
平方数 = [x**2 for x in range(1, 11)]
print(f"\n1-10的平方数: {平方数}")

# 过滤偶数
偶数 = [x for x in range(1, 21) if x % 2 == 0]
print(f"1-20的偶数: {偶数}")

# 嵌套循环
矩阵 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
扁平化 = [元素 forin 矩阵 for 元素 in 行]
print(f"矩阵: {矩阵}")
print(f"扁平化后: {扁平化}")

# 条件表达式
结果 = ["偶数" if x % 2 == 0 else "奇数" for x in range(1, 11)]
print(f"奇偶判断: {结果}")

# 列表的实际应用
def 处理学生成绩(成绩列表):
    """处理学生成绩列表,提供统计信息"""
    if not 成绩列表:
        return {"错误": "成绩列表为空"}

    统计信息 = {
        "总人数": len(成绩列表),
        "平均分": sum(成绩列表) / len(成绩列表),
        "最高分": max(成绩列表),
        "最低分": min(成绩列表),
        "及格人数": len([成绩 for 成绩 in 成绩列表 if 成绩 >= 60]),
        "优秀人数": len([成绩 for 成绩 in 成绩列表 if 成绩 >= 90]),
    }

    # 计算分数段分布
    分数段 = [0, 60, 70, 80, 90, 101]  # 左闭右开
    分数段标签 = ["不及格", "及格", "中等", "良好", "优秀"]

    分布 = {}
    for i in range(len(分数段标签)):
        下限 = 分数段[i]
        上限 = 分数段[i + 1]
        人数 = len([成绩 for 成绩 in 成绩列表 if 下限 <= 成绩 < 上限])
        分布[分数段标签[i]] = 人数

    统计信息["分数分布"] = 分布

    return 统计信息

# 测试学生成绩处理
学生成绩 = [85, 92, 78, 45, 67, 88, 95, 56, 72, 100, 61, 89]
统计结果 = 处理学生成绩(学生成绩)

print("\n学生成绩统计:")
print(f"总人数: {统计结果['总人数']}")
print(f"平均分: {统计结果['平均分']:.1f}")
print(f"最高分: {统计结果['最高分']}")
print(f"最低分: {统计结果['最低分']}")
print(f"及格人数: {统计结果['及格人数']}")
print(f"优秀人数: {统计结果['优秀人数']}")
print("分数分布:")
for 等级, 人数 in 统计结果["分数分布"].items():
    print(f"  {等级}: {人数}人")

元组(tuple):不可变的序列

元组与列表类似,但是不可变(immutable)。一旦创建,就不能修改、添加或删除元素。

python
# 元组的创建
空元组 = ()
单个元素元组 = (1,)  # 注意逗号!(1)会被认为是整数1
多个元素元组 = (1, 2, 3, 4, 5)
混合元组 = (1, "two", 3.0, [4, 5])  # 元组可以包含可变元素
生成元组 = tuple("Python")  # ('P', 'y', 't', 'h', 'o', 'n')

print(f"空元组: {空元组}")
print(f"单个元素元组: {单个元素元组}")
print(f"多个元素元组: {多个元素元组}")
print(f"混合元组: {混合元组}")
print(f"生成元组: {生成元组}")

# 元组基本操作
元组 = (10, 20, 30, 40, 50)

print(f"\n元组: {元组}")
print(f"长度: {len(元组)}")
print(f"第一个元素: {元组[0]}")
print(f"最后一个元素: {元组[-1]}")
print(f"切片: {元组[1:4]}")
print(f"索引为2的元素: {元组[2]}")

# 元组是不可变的,以下操作会引发错误
# 元组[0] = 100  # TypeError: 'tuple' object does not support item assignment
# 元组.append(60)  # AttributeError: 'tuple' object has no attribute 'append'

# 但是,如果元组包含可变对象,可以修改可变对象的内容
可变元组 = ([1, 2, 3], {"a": 1, "b": 2})
print(f"\n可变元组: {可变元组}")
可变元组[0].append(4)  # 可以修改列表
可变元组[1]["c"] = 3   # 可以修改字典
print(f"修改后可变元组: {可变元组}")

# 元组解包
点坐标 = (10, 20, 30)
x, y, z = 点坐标
print(f"\n点坐标: {点坐标}")
print(f"解包: x={x}, y={y}, z={z}")

# 使用*收集多余的值
第一个, *中间, 最后一个 = (1, 2, 3, 4, 5, 6)
print(f"第一个: {第一个}, 中间: {中间}, 最后一个: {最后一个}")

# 交换变量值
a, b = 1, 2
print(f"\n交换前: a={a}, b={b}")
a, b = b, a  # 实际上是元组解包
print(f"交换后: a={a}, b={b}")

# 元组作为函数返回值
def 获取用户信息():
    """返回用户信息(元组形式)"""
    return ("张三", 25, "北京")

姓名, 年龄, 城市 = 获取用户信息()
print(f"\n用户信息: 姓名={姓名}, 年龄={年龄}, 城市={城市}")

# 元组的性能优势
# 元组比列表更轻量,创建和访问速度更快
import time

列表测试 = list(range(1000000))
元组测试 = tuple(range(1000000))

# 创建时间测试
开始时间 = time.time()
列表副本 = list(列表测试)
列表耗时 = time.time() - 开始时间

开始时间 = time.time()
元组副本 = tuple(元组测试)
元组耗时 = time.time() - 开始时间

print(f"\n性能测试:")
print(f"列表创建时间: {列表耗时:.6f}秒")
print(f"元组创建时间: {元组耗时:.6f}秒")

# 元组的实际应用
def 获取统计信息(数据列表):
    """计算数据的统计信息,返回元组"""
    if not 数据列表:
        return None

    平均值 = sum(数据列表) / len(数据列表)
    最大值 = max(数据列表)
    最小值 = min(数据列表)
    中位数 = sorted(数据列表)[len(数据列表) // 2]

    return (平均值, 最大值, 最小值, 中位数, len(数据列表))

def 格式化货币(金额):
    """格式化货币金额,返回元组(整数部分,小数部分)"""
    整数部分 = int(金额)
    小数部分 = round((金额 - 整数部分) * 100)
    return (整数部分, 小数部分)

# 测试
测试数据 = [23.5, 45.2, 67.8, 89.1, 34.6, 56.7]
统计 = 获取统计信息(测试数据)
print(f"\n数据统计: {测试数据}")
print(f"统计结果: 平均值={统计[0]:.2f}, 最大值={统计[1]}, 最小值={统计[2]}, 中位数={统计[3]}, 数量={统计[4]}")

价格 = 1234.56
整数部分, 小数部分 = 格式化货币(价格)
print(f"\n价格: {价格}")
print(f"格式化: {整数部分}{小数部分:02d}分")  # 1234元56分

# 命名元组(NamedTuple):给元组元素起名字
from collections import namedtuple

# 定义命名元组类型
= namedtuple('点', ['x', 'y', 'z'])
颜色 = namedtuple('颜色', ['红', '绿', '蓝', '透明度'])

# 创建命名元组实例
点1 = 点(10, 20, 30)
颜色1 = 颜色(255, 0, 0, 255)

print(f"\n命名元组示例:")
print(f"点1: x={点1.x}, y={点1.y}, z={点1.z}")
print(f"颜色1: RGB({颜色1.红}, {颜色1.绿}, {颜色1.蓝}), 透明度={颜色1.透明度}")

# 可以像普通元组一样使用
print(f"点1[0]: {点1[0]}")  # 10
print(f"点1的字段: {点1._fields}")  # ('x', 'y', 'z')

# 替换部分值
点2 = 点1._replace(y=50, z=100)
print(f"点2: {点2}")

# 转换为字典
点字典 = 点2._asdict()
print(f"点2的字典形式: {点字典}")

3.7 复合数据类型:字典、集合

字典(dict):键值对的映射

字典是Python中最强大的内置数据结构之一,它存储键值对(key-value pairs),提供快速的查找能力。

python
# 字典的创建
空字典 = {}
简单字典 = {"name": "张三", "age": 25, "city": "北京"}
构造字典 = dict(name="李四", age=30, city="上海")
元组列表转换 = dict([("a", 1), ("b", 2), ("c", 3)])
键列表转换 = dict.fromkeys(["姓名", "年龄", "城市"], "未知")

print(f"空字典: {空字典}")
print(f"简单字典: {简单字典}")
print(f"构造字典: {构造字典}")
print(f"元组列表转换: {元组列表转换}")
print(f"键列表转换: {键列表转换}")

# 字典基本操作
学生 = {
    "姓名": "王五",
    "年龄": 22,
    "专业": "计算机科学",
    "成绩": {"数学": 90, "英语": 85, "编程": 95}
}

print(f"\n学生信息: {学生}")

# 访问元素
print(f"姓名: {学生['姓名']}")
print(f"数学成绩: {学生['成绩']['数学']}")

# 使用get方法安全访问
print(f"年龄: {学生.get('年龄')}")
print(f"地址: {学生.get('地址', '未提供')}")  # 提供默认值

# 修改元素
学生["年龄"] = 23
学生["成绩"]["数学"] = 95
学生["邮箱"] = "wangwu@example.com"  # 添加新键值对
print(f"修改后: {学生}")

# 删除元素
删除的值 = 学生.pop("邮箱")  # 删除并返回键对应的值
print(f"删除邮箱: {删除的值}, 剩余: {学生}")

键, 值 = 学生.popitem()  # 删除并返回最后一个键值对
print(f"popitem: 键={}, 值={}, 剩余: {学生}")

# 重新添加被删除的项
学生[键] =

# 字典常用方法
print(f"\n学生字典: {学生}")
print(f"所有键: {list(学生.keys())}")
print(f"所有值: {list(学生.values())}")
print(f"所有键值对: {list(学生.items())}")

print(f"键数量: {len(学生)}")
print(f"包含'姓名'键: {'姓名' in 学生}")
print(f"包含'地址'键: {'地址' in 学生}")

# 遍历字典
print("\n遍历字典:")
forin 学生:
    print(f"  键: {}, 值: {学生[键]}")

print("\n遍历键值对:")
for 键, 值 in 学生.items():
    print(f"  {}: {}")

# 字典推导式
# 基本语法:{键表达式: 值表达式 for 变量 in 可迭代对象 if 条件}

# 创建数字平方字典
平方字典 = {x: x**2 for x in range(1, 11)}
print(f"\n1-10的平方字典: {平方字典}")

# 转换列表为字典
列表1 = ["a", "b", "c"]
列表2 = [1, 2, 3]
合并字典 = {k: v for k, v in zip(列表1, 列表2)}
print(f"合并字典: {合并字典}")

# 过滤字典
原始字典 = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}
偶数字典 = {k: v for k, v in 原始字典.items() if v % 2 == 0}
print(f"原始字典: {原始字典}")
print(f"偶数字典: {偶数字典}")

# 字典的实际应用
def 统计词频(文本):
    """统计文本中单词的频率"""
    # 清理文本:转换为小写,去除标点
    清理后文本 = ""
    for 字符 in 文本.lower():
        if 字符.isalpha() or 字符.isspace():
            清理后文本 += 字符

    # 分割单词
    单词列表 = 清理后文本.split()

    # 统计词频
    词频 = {}
    for 单词 in 单词列表:
        词频[单词] = 词频.get(单词, 0) + 1

    return 词频

def 合并学生信息(学生列表):
    """合并多个学生的信息,处理重复和冲突"""
    合并结果 = {}

    for 学生 in 学生列表:
        学号 = 学生["学号"]

        if 学号 not in 合并结果:
            # 第一次见到这个学号,直接添加
            合并结果[学号] = 学生
        else:
            # 合并冲突,保留最新信息
            现有信息 = 合并结果[学号]
            for 键, 值 in 学生.items():
                ifnot in 现有信息 or== "最后更新":
                    # 新键或最后更新时间,总是更新
                    现有信息[键] =
                elif isinstance(值, dict) and isinstance(现有信息.get(键), dict):
                    # 如果都是字典,递归合并
                    现有信息[键].update(值)
                elif 键.startswith("最新_"):
                    # 以"最新_"开头的键,总是更新
                    现有信息[键] =

    return 合并结果

# 测试词频统计
测试文本 = "Python is great. Python is powerful. Python is easy to learn."
词频结果 = 统计词频(测试文本)
print("\n词频统计:")
print(f"文本: {测试文本}")
print("词频:")
for 单词, 频率 in sorted(词频结果.items(), key=lambda x: x[1], reverse=True):
    print(f"  {单词}: {频率}")

# 测试学生信息合并
学生列表 = [
    {"学号": "001", "姓名": "张三", "年龄": 20, "成绩": {"数学": 90}, "最后更新": "2023-01-01"},
    {"学号": "002", "姓名": "李四", "年龄": 21, "最后更新": "2023-01-02"},
    {"学号": "001", "姓名": "张三", "年龄": 21, "成绩": {"英语": 85}, "最新_状态": "活跃", "最后更新": "2023-01-03"},
    {"学号": "003", "姓名": "王五", "年龄": 22, "最后更新": "2023-01-04"},
]

合并后 = 合并学生信息(学生列表)
print("\n学生信息合并:")
for 学号, 信息 in 合并后.items():
    print(f"  学号{学号}: {信息}")

集合(set):无序不重复的集合

集合是一个无序的、不重复元素的集合。它支持数学上的集合操作,如并集、交集、差集等。

python
# 集合的创建
空集合 = set()  # 注意:{}创建的是空字典,不是空集合
数字集合 = {1, 2, 3, 4, 5}
列表转集合 = set([1, 2, 2, 3, 3, 3, 4, 5])  # 自动去重
字符串转集合 = set("hello")  # {'h', 'e', 'l', 'o'}

print(f"空集合: {空集合}")
print(f"数字集合: {数字集合}")
print(f"列表转集合: {列表转集合}")
print(f"字符串转集合: {字符串转集合}")

# 集合基本操作
集合A = {1, 2, 3, 4, 5}
集合B = {4, 5, 6, 7, 8}

print(f"\n集合A: {集合A}")
print(f"集合B: {集合B}")

# 添加元素
集合A.add(6)
集合A.update([7, 8, 9])  # 添加多个元素
print(f"添加后集合A: {集合A}")

# 删除元素
集合A.remove(9)  # 如果元素不存在会引发KeyError
集合A.discard(10)  # 安全删除,元素不存在也不会报错
删除的元素 = 集合A.pop()  # 随机删除并返回一个元素
print(f"删除后集合A: {集合A}, 删除的元素: {删除的元素}")

# 清空集合
集合C = {1, 2, 3}
集合C.clear()
print(f"清空后集合C: {集合C}")

# 集合运算
print(f"\n集合运算:")
print(f"A: {集合A}")
print(f"B: {集合B}")

print(f"并集 A | B: {集合A | 集合B}")  # 或 集合A.union(集合B)
print(f"交集 A & B: {集合A & 集合B}")  # 或 集合A.intersection(集合B)
print(f"差集 A - B: {集合A - 集合B}")  # 在A中但不在B中
print(f"差集 B - A: {集合B - 集合A}")  # 在B中但不在A中
print(f"对称差集 A ^ B: {集合A ^ 集合B}")  # 只在A或只在B中,不在两者交集

# 集合关系
print(f"\n集合关系:")
print(f"A ⊆ B: {集合A.issubset(集合B)}")  # A是否是B的子集
print(f"B ⊇ A: {集合B.issuperset(集合A)}")  # B是否是A的超集
print(f"A ∩ B = ∅: {集合A.isdisjoint(集合B)}")  # A和B是否没有交集

# 集合推导式
# 基本语法:{表达式 for 变量 in 可迭代对象 if 条件}

# 创建平方数集合
平方集合 = {x**2 for x in range(1, 11)}
print(f"\n1-10的平方集合: {平方集合}")

# 过滤奇数
偶数集合 = {x for x in range(1, 21) if x % 2 == 0}
print(f"1-20的偶数集合: {偶数集合}")

# 集合的实际应用
def 查找共同好友(用户好友字典):
    """查找所有用户的共同好友"""
    if not 用户好友字典:
        return set()

    # 获取所有用户的集合
    用户集合 = set(用户好友字典.keys())

    # 如果没有至少两个用户,返回空集
    if len(用户集合) < 2:
        return set()

    # 计算所有用户的共同好友
    共同好友 = None
    for 用户, 好友集合 in 用户好友字典.items():
        if 共同好友 is None:
            共同好友 = 好友集合.copy()
        else:
            共同好友 &= 好友集合  # 取交集

    return 共同好友 or set()

def 去重并排序(数据列表, 保留顺序=False):
    """去除列表中的重复元素,可选择是否保留原始顺序"""
    if 保留顺序:
        # 保留顺序的去重
        已看到 = set()
        结果 = []
        for 元素 in 数据列表:
            if 元素 not in 已看到:
                已看到.add(元素)
                结果.append(元素)
        return 结果
    else:
        # 不保留顺序,直接使用集合去重
        return sorted(set(数据列表))  # 返回排序后的列表

def 查找无效数据(原始列表, 有效值集合):
    """查找不在有效值集合中的无效数据"""
    原始集合 = set(原始列表)
    无效数据 = 原始集合 - 有效值集合
    return 无效数据

# 测试共同好友查找
用户好友 = {
    "张三": {"李四", "王五", "赵六", "钱七"},
    "李四": {"张三", "王五", "孙八"},
    "王五": {"张三", "李四", "赵六"},
    "赵六": {"张三", "王五", "钱七"},
}

共同好友 = 查找共同好友(用户好友)
print("\n共同好友查找:")
print("用户好友关系:")
for 用户, 好友 in 用户好友.items():
    print(f"  {用户}: {好友}")
print(f"所有用户的共同好友: {共同好友}")

# 测试去重
测试列表 = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
print(f"\n去重测试:")
print(f"原始列表: {测试列表}")
print(f"去重不保序: {去重并排序(测试列表, 保留顺序=False)}")
print(f"去重保序: {去重并排序(测试列表, 保留顺序=True)}")

# 测试无效数据查找
有效状态集合 = {"待处理", "处理中", "已完成", "已取消"}
实际状态列表 = ["待处理", "处理中", "已完成", "未知状态", "待处理", "无效状态"]

无效状态 = 查找无效数据(实际状态列表, 有效状态集合)
print(f"\n无效数据查找:")
print(f"有效状态: {有效状态集合}")
print(f"实际状态: {实际状态列表}")
print(f"无效状态: {无效状态}")

# 冰冻集合(frozenset):不可变的集合
# 可以像元组一样用作字典的键
冰冻集合A = frozenset([1, 2, 3, 4])
冰冻集合B = frozenset([3, 4, 5, 6])

print(f"\n冰冻集合:")
print(f"冰冻集合A: {冰冻集合A}")
print(f"冰冻集合B: {冰冻集合B}")
print(f"并集: {冰冻集合A | 冰冻集合B}")
print(f"交集: {冰冻集合A & 冰冻集合B}")

# 冰冻集合作为字典的键
字典键测试 = {
    冰冻集合A: "集合A",
    冰冻集合B: "集合B",
    frozenset(["a", "b"]): "字母集合"
}
print(f"\n冰冻集合作为字典键: {字典键测试}")

3.8 类型检查与内存管理简介

类型检查:确保代码的健壮性

类型检查可以帮助我们在代码运行前发现潜在的类型错误,提高代码的可靠性。

python
# 使用type()函数检查类型
变量 = 100
print(f"变量 = {变量}")
print(f"类型: {type(变量)}")
print(f"是否为整数: {isinstance(变量, int)}")
print(f"是否为数字(整数或浮点数): {isinstance(变量, (int, float))}")

# 不同类型检查示例
测试数据 = [
    100,              # 整数
    3.14,             # 浮点数
    "Hello",          # 字符串
    [1, 2, 3],        # 列表
    (1, 2, 3),        # 元组
    {"a": 1},         # 字典
    {1, 2, 3},        # 集合
    True,             # 布尔值
    None              # None
]

print("\n类型检查示例:")
for 数据 in 测试数据:
    print(f"  数据: {数据!r:15} 类型: {type(数据).__name__:10} isinstance检查: {isinstance(数据, (int, float, str))}")

# 使用isinstance()进行类型检查
def 安全加法(a, b):
    """安全的加法函数,检查参数类型"""
    if not isinstance(a, (int, float, complex)):
        raise TypeError(f"参数a必须是数字类型,实际是{type(a).__name__}")
    if not isinstance(b, (int, float, complex)):
        raise TypeError(f"参数b必须是数字类型,实际是{type(b).__name__}")

    return a + b

print("\n安全加法测试:")
try:
    结果1 = 安全加法(10, 20)
    print(f"  10 + 20 = {结果1}")

    结果2 = 安全加法(3.14, 2.86)
    print(f"  3.14 + 2.86 = {结果2}")

    结果3 = 安全加法("10", 20)  # 会引发TypeError
    print(f"  '10' + 20 = {结果3}")
except TypeError as e:
    print(f"  错误: {e}")

# 类型注解(Python 3.5+)
# 类型注解不会影响运行时,但可以帮助静态类型检查器(如mypy)发现错误

def 计算面积(半径: float) -> float:
    """计算圆的面积

    参数:
        半径: 圆的半径,应为浮点数

    返回:
        圆的面积
    """
    if 半径 <= 0:
        raise ValueError("半径必须大于0")
    return 3.14159 * 半径 ** 2

def 处理用户数据(用户列表: list[dict]) -> tuple[int, list[str]]:
    """处理用户数据

    参数:
        用户列表: 用户字典列表

    返回:
        (用户数量, 用户名列表)
    """
    用户数量 = len(用户列表)
    用户名列表 = [用户.get("姓名", "未知") for 用户 in 用户列表]
    return 用户数量, 用户名列表

# 测试类型注解函数
print("\n类型注解函数测试:")
面积 = 计算面积(5.0)
print(f"  半径5.0的圆面积: {面积:.2f}")

用户数据 = [
    {"姓名": "张三", "年龄": 25},
    {"姓名": "李四", "年龄": 30},
    {"年龄": 35},  # 没有姓名的用户
]
数量, 名称列表 = 处理用户数据(用户数据)
print(f"  用户数量: {数量}, 用户名列表: {名称列表}")

# 使用Typing模块进行更复杂的类型注解
from typing import List, Dict, Tuple, Optional, Union, Any

def 复杂数据处理(
    数据列表: List[Union[int, float]],
    配置: Optional[Dict[str, Any]] = None
) -> Tuple[int, float]:
    """复杂数据处理函数

    参数:
        数据列表: 整数或浮点数列表
        配置: 可选的配置字典

    返回:
        (数据数量, 平均值)
    """
    if not 数据列表:
        return 0, 0.0

    数量 = len(数据列表)
    总和 = sum(数据列表)
    平均值 = 总和 / 数量

    if 配置:
        # 处理配置
        精度 = 配置.get("精度", 2)
        平均值 = round(平均值, 精度)

    return 数量, 平均值

# 测试复杂数据处理
数据 = [1, 2.5, 3, 4.5, 5]
配置 = {"精度": 3}
数量, 平均值 = 复杂数据处理(数据, 配置)
print(f"\n复杂数据处理:")
print(f"  数据: {数据}")
print(f"  配置: {配置}")
print(f"  结果: 数量={数量}, 平均值={平均值}")

Python内存管理简介

Python使用自动内存管理(垃圾回收),但了解其基本原理有助于编写更高效的代码。

python
import sys
import gc  # 垃圾回收模块

# 查看对象的内存占用
def 查看内存占用(对象):
    """查看对象的内存占用大小"""
    return sys.getsizeof(对象)

print("各种对象的内存占用:")
print(f"  整数 100: {查看内存占用(100)} 字节")
print(f"  浮点数 3.14: {查看内存占用(3.14)} 字节")
print(f"  字符串 'Hello': {查看内存占用('Hello')} 字节")
print(f"  空列表: {查看内存占用([])} 字节")
print(f"  空字典: {查看内存占用({})} 字节")
print(f"  空元组: {查看内存占用(())} 字节")
print(f"  空集合: {查看内存占用(set())} 字节")

# 引用计数
print("\n引用计数演示:")

# 创建对象
a = [1, 2, 3]  # 引用计数为1
print(f"  创建列表a: id={id(a)}, 引用计数=1")

b = a  # 引用计数增加为2
print(f"  b = a后: id(a)={id(a)}, id(b)={id(b)}, 相同对象")

c = a  # 引用计数增加为3
print(f"  c = a后: 引用计数=3")

# 删除引用
del b  # 引用计数减少为2
print(f"  del b后: 引用计数=2")

a = None  # 引用计数减少为1
print(f"  a = None后: 引用计数=1")

c = None  # 引用计数减少为0,对象被回收
print(f"  c = None后: 引用计数=0,对象被垃圾回收")

# 循环引用问题
print("\n循环引用演示:")

class 节点:
    def __init__(self, 名称):
        self.名称 = 名称
        self.下一个 = None

    def __repr__(self):
        return f"节点({self.名称})"

# 创建循环引用
节点A = 节点("A")
节点B = 节点("B")
节点A.下一个 = 节点B
节点B.下一个 = 节点A  # 循环引用!

print(f"  创建节点A和节点B,并建立循环引用")
print(f"  节点A: {节点A}")
print(f"  节点B: {节点B}")
print(f"  节点A.下一个: {节点A.下一个}")
print(f"  节点B.下一个: {节点B.下一个}")

# 删除引用
节点A = None
节点B = None
print(f"  删除节点A和节点B的引用")

# 手动触发垃圾回收
回收前计数 = gc.get_count()
print(f"\n  手动触发垃圾回收前: {回收前计数}")
回收的对象 = gc.collect()
print(f"  垃圾回收收集的对象: {回收的对象}")
回收后计数 = gc.get_count()
print(f"  手动触发垃圾回收后: {回收后计数}")

# 内存管理最佳实践
def 内存管理建议():
    """内存管理的最佳实践建议"""
    建议 = """
内存管理最佳实践:
1. 及时删除不再需要的引用
   - 使用 del 语句或赋值为 None
   - 函数局部变量在函数结束时自动删除

2. 避免循环引用
   - 使用弱引用(weakref)模块处理循环引用
   - 对于数据结构,考虑使用双向链表替代相互引用

3. 使用生成器处理大数据
   - 生成器一次只产生一个值,节省内存
   - 使用 (x for x in range(1000000)) 而不是 list(range(1000000))

4. 使用适当的数据结构
   - 数组(array)比列表更节省内存(存储单一类型)
   - 使用元组替代列表,如果数据不需要修改

5. 分块处理大数据
   - 不要一次性加载所有数据到内存
   - 分批读取和处理数据

6. 使用内置函数和方法
   - 内置函数通常用C实现,更高效
   - 如 sum(), map(), filter() 等
"""
    return 建议

print(内存管理建议())

# 演示生成器节省内存
print("生成器内存占用演示:")
列表 = [i for i in range(1000000)]  # 列表推导式
生成器 = (i for i in range(1000000))  # 生成器表达式

print(f"  列表内存占用: {查看内存占用(列表):,} 字节")
print(f"  生成器内存占用: {查看内存占用(生成器):,} 字节")

# 演示分块处理大数据
def 分块处理文件(文件名, 块大小=1024):
    """分块读取大文件,避免一次性加载到内存"""
    with open(文件名, 'r', encoding='utf-8') as 文件:
        while True:
= 文件.read(块_size)
            if not 块:
                break
            yield

# 实际应用:缓存管理
class 智能缓存:
    """简单的缓存管理器"""

    def __init__(self, 最大大小=100):
        self.缓存 = {}
        self.最大大小 = 最大大小
        self.使用顺序 = []  # 记录使用顺序,用于LRU(最近最少使用)算法

    def 获取(self, 键):
        """获取缓存值,如果存在则更新使用顺序"""
        ifin self.缓存:
            # 更新使用顺序
            ifin self.使用顺序:
                self.使用顺序.remove(键)
            self.使用顺序.append(键)
            return self.缓存[键]
        return None

    def 设置(self, 键, 值):
        """设置缓存值,如果缓存已满则删除最久未使用的项"""
        if len(self.缓存) >= self.最大大小 andnot in self.缓存:
            # 删除最久未使用的项
            最久未使用 = self.使用顺序.pop(0)
            del self.缓存[最久未使用]

        self.缓存[键] =
        ifin self.使用顺序:
            self.使用顺序.remove(键)
        self.使用顺序.append(键)

    def 清理(self):
        """清理缓存"""
        self.缓存.clear()
        self.使用顺序.clear()

# 测试缓存管理器
print("\n智能缓存演示:")
缓存 = 智能缓存(最大大小=3)

# 添加数据
for i in range(5):
= f"键{i}"
= f"值{i}"
    缓存.设置(键, 值)
    print(f"  设置 {} = {}")
    print(f"  当前缓存: {缓存.缓存}")
    print(f"  使用顺序: {缓存.使用顺序}")

# 获取数据
print(f"\n获取键2: {缓存.获取('键2')}")
print(f"获取后使用顺序: {缓存.使用顺序}")

# 清理缓存
缓存.清理()
print(f"清理后缓存大小: {len(缓存.缓存)}")

总结:打好Python编程的基础

通过本章的学习,你已经掌握了Python编程的基础构件:

  1. 变量与赋值 - 数据的命名和存储
  2. 基本数据类型 - 整数、浮点数、字符串的用法和特性
  3. 数据类型转换 - 在不同类型间灵活转换
  4. 注释与代码风格 - 写出清晰可维护的代码
  5. 运算符 - 数据的基本操作和比较
  6. 复合数据类型 - 列表、元组、字典、集合的强大功能
  7. 类型检查与内存管理 - 编写健壮高效代码的基础

记住这些核心要点:

  • Python是动态类型语言:变量类型可以在运行时改变
  • 一切都是对象:Python中所有数据都是对象,有类型、有方法
  • 理解引用语义:变量是对象的引用,而不是对象本身
  • 选择合适的数据结构:不同问题适合不同的数据结构
  • 遵循PEP 8风格:写出专业、易读的代码

实践是学习编程的唯一途径。现在,尝试完成以下练习来巩固所学知识:

练习题

  1. 创建一个学生信息管理系统,使用字典存储学生信息
  2. 编写一个函数,统计一段文本中每个单词出现的次数
  3. 实现一个简单的购物车系统,支持添加商品、计算总价、应用折扣
  4. 使用列表推导式生成1-100中所有能被3整除但不能被5整除的数字
  5. 创建一个函数,接受任意数量的参数,返回它们的类型和值

下一步学习

在下一章中,我们将学习控制流,包括条件语句和循环语句。这将使你能够编写更复杂的逻辑,让程序根据不同的条件做出决策,以及重复执行某些操作。

记住:编程就像学习一门新语言,需要不断练习。不要害怕犯错,每个错误都是学习的机会。你已经迈出了坚实的第一步,继续前进吧!


本文是《Python入门与进阶实践》的第三章,涵盖了Python基础语法与数据类型的核心内容。在实际编程中,你会不断回顾和使用这些基础知识,所以请确保真正理解每个概念。如果有任何疑问,欢迎在评论区讨论。

相关资源

代码下载本章完整代码示例

热爱生活,喜好美食,追求未来!