Python基础语法与数据类型:编程世界的基石与积木
数据类型是编程的基石,理解它们就像建筑师了解材料特性一样重要。掌握基础语法,你就能用Python搭建任何你想象的数字世界。
前言:从"Hello World"到真正的编程
还记得上一章我们写的print("Hello World")吗?这就像是站在编程世界的门口打了声招呼。现在,我们要真正走进这个世界,学习它的基本规则和构造材料。
编程的本质是什么? 很多人可能会说是"写代码",但实际上,编程是用计算机能理解的方式描述问题和解决方案。而Python的数据类型和基础语法,就是我们描述世界的"词汇表"和"语法规则"。
让我用一个简单的比喻来解释:如果把编程比作建造一座大厦,那么:
- 变量是给建筑材料起的名字
- 数据类型是建筑材料的种类(砖头、水泥、钢筋)
- 运算符是连接材料的方法(砌墙、浇筑)
- 注释是建筑图纸上的说明文字
在这一章,我们将一起探索Python世界的这些基础构件,为后续更复杂的编程打下坚实的基础。
3.1 变量与赋值:给数据起个好名字
什么是变量?
想象一下你去超市购物。你不会对收银员说:"请把我刚才从第三排货架拿的那个蓝色包装、重量500克的东西结账",而是会说:"请把这包薯片结账"。这里的"薯片"就是一个变量名,它代表了一包具体的薯片。
在Python中,变量就是数据的名字。通过这个名字,我们可以引用和操作数据。
# 变量赋值的基本语法
商品名称 = "薯片" # 字符串类型变量
商品价格 = 8.5 # 浮点数类型变量
商品数量 = 3 # 整数类型变量
# 使用变量进行计算
总价 = 商品价格 * 商品数量
print(f"您购买了{商品数量}包{商品名称},总价为{总价}元")
# 输出:您购买了3包薯片,总价为25.5元Python变量的特点
1. 动态类型:变量类型可以随时改变
# 同一个变量名可以存储不同类型的数据
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.02. 引用语义:变量是数据的"标签"
# 理解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}") # 输出: True3. 命名规则与最佳实践
# 有效的变量名
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元多重赋值与交换技巧
# 传统方式交换两个变量的值
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):精确的计数
整数是编程中最基础的数据类型,用于表示没有小数部分的数字。
# 整数的各种表示形式
十进制 = 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):带小数的实数
浮点数用于表示实数(带小数点的数字),但在计算机中是以近似值存储的。
# 浮点数的表示
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中用于表示文本的数据类型,功能极其强大。
# 字符串的多种创建方式
字符串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提供了内置函数来进行显式的类型转换。
# 整数与浮点数之间的转换
整数 = 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在某些情况下会自动进行类型转换,这称为隐式类型转换或类型强制转换。
# 整数和浮点数运算时的隐式转换
整数 = 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类型转换的实际应用
# 应用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 注释与代码风格:写出人类也能读懂的代码
注释的艺术
注释是写给人类看的代码说明,好的注释能让代码更易理解和维护。
# 单行注释:解释下面这行代码的作用
# 计算圆的面积
半径 = 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官方的代码风格指南,遵循它能让你的代码更专业、更易读。
"""
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.成绩)}"代码格式化工具
"""
使用工具自动格式化代码
"""
# 安装代码格式化工具
# 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 运算符:算术、比较、逻辑
算术运算符
# 基本算术运算符
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}元")比较运算符
# 基本比较运算符
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" '{用户名}' 验证通过")逻辑运算符
# 基本逻辑运算符
# 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 '拒绝'}")身份运算符和成员运算符
# 身份运算符: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中最常用、最灵活的数据结构之一,可以存储任意类型的元素,并且可以动态调整大小。
# 列表的创建
空列表 = []
数字列表 = [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]]
扁平化 = [元素 for 行 in 矩阵 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)。一旦创建,就不能修改、添加或删除元素。
# 元组的创建
空元组 = ()
单个元素元组 = (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),提供快速的查找能力。
# 字典的创建
空字典 = {}
简单字典 = {"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遍历字典:")
for 键 in 学生:
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():
if 键 not 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):无序不重复的集合
集合是一个无序的、不重复元素的集合。它支持数学上的集合操作,如并集、交集、差集等。
# 集合的创建
空集合 = 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 类型检查与内存管理简介
类型检查:确保代码的健壮性
类型检查可以帮助我们在代码运行前发现潜在的类型错误,提高代码的可靠性。
# 使用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使用自动内存管理(垃圾回收),但了解其基本原理有助于编写更高效的代码。
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, 键):
"""获取缓存值,如果存在则更新使用顺序"""
if 键 in self.缓存:
# 更新使用顺序
if 键 in self.使用顺序:
self.使用顺序.remove(键)
self.使用顺序.append(键)
return self.缓存[键]
return None
def 设置(self, 键, 值):
"""设置缓存值,如果缓存已满则删除最久未使用的项"""
if len(self.缓存) >= self.最大大小 and 键 not in self.缓存:
# 删除最久未使用的项
最久未使用 = self.使用顺序.pop(0)
del self.缓存[最久未使用]
self.缓存[键] = 值
if 键 in 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编程的基础构件:
- 变量与赋值 - 数据的命名和存储
- 基本数据类型 - 整数、浮点数、字符串的用法和特性
- 数据类型转换 - 在不同类型间灵活转换
- 注释与代码风格 - 写出清晰可维护的代码
- 运算符 - 数据的基本操作和比较
- 复合数据类型 - 列表、元组、字典、集合的强大功能
- 类型检查与内存管理 - 编写健壮高效代码的基础
记住这些核心要点:
- Python是动态类型语言:变量类型可以在运行时改变
- 一切都是对象:Python中所有数据都是对象,有类型、有方法
- 理解引用语义:变量是对象的引用,而不是对象本身
- 选择合适的数据结构:不同问题适合不同的数据结构
- 遵循PEP 8风格:写出专业、易读的代码
实践是学习编程的唯一途径。现在,尝试完成以下练习来巩固所学知识:
练习题
- 创建一个学生信息管理系统,使用字典存储学生信息
- 编写一个函数,统计一段文本中每个单词出现的次数
- 实现一个简单的购物车系统,支持添加商品、计算总价、应用折扣
- 使用列表推导式生成1-100中所有能被3整除但不能被5整除的数字
- 创建一个函数,接受任意数量的参数,返回它们的类型和值
下一步学习
在下一章中,我们将学习控制流,包括条件语句和循环语句。这将使你能够编写更复杂的逻辑,让程序根据不同的条件做出决策,以及重复执行某些操作。
记住:编程就像学习一门新语言,需要不断练习。不要害怕犯错,每个错误都是学习的机会。你已经迈出了坚实的第一步,继续前进吧!
本文是《Python入门与进阶实践》的第三章,涵盖了Python基础语法与数据类型的核心内容。在实际编程中,你会不断回顾和使用这些基础知识,所以请确保真正理解每个概念。如果有任何疑问,欢迎在评论区讨论。
相关资源:
代码下载:本章完整代码示例