文章目录

摘要:本文是Python入门教程,系统讲解了字面量、注释、变量与标识符、数据类型、类型转换、运算符、字符串操作、文件读写及数据可视化等核心基础知识。通过大量代码示例和实战技巧,帮助初学者快速掌握Python编程基础。

一、字面量

什么是字面量?用一句话来说:字面量就是你在代码里直接写出来的固定值

# 这些都是字面量
123          # 整数字面量
3.14         # 浮点数字面量
"hello"      # 字符串字面量
True         # 布尔值字面量
[1, 2, 3]    # 列表字面量
{"name": "张三"}  # 字典字面量

各种类型的字面量

# 整数字面量
age = 18
negative = -5
big_number = 1000000

# 浮点数字面量(小数)
pi = 3.14159
price = 99.99
scientific = 1.5e3  # 科学计数法,等于1500.0

# 字符串字面量
name = "小明"
message = 'Hello World'
multiline = """这是
多行
字符串"""

# 布尔值字面量(只有两个)
is_student = True
is_working = False

# 特殊字面量:None(表示"空"或"没有值")
result = None

二、注释

注释用来批注代码,让别人也能看懂你的代码,经常写注释是一个好习惯:

单行注释

# 这是单行注释,用井号开头
print("Hello")  # 也可以写在代码后面

# 计算圆的面积
radius = 5
area = 3.14 * radius ** 2  # ** 是次方运算

多行注释

"""
这是多行注释
可以写很多行
通常用三个引号
"""

'''
单引号的三引号也可以
但一般用双引号比较多
'''

# 实际使用场景
def calculate_area(radius):
    """
    计算圆的面积
    参数:radius - 圆的半径
    返回:圆的面积
    """
    return 3.14 * radius ** 2

快捷键:在VSCode或PyCharm里,选中多行代码按Ctrl + /可以快速注释/取消注释。

三、变量&标识符

变量用来保存数据,请注意python的变量没有类型,只有数据才会有类型!

变量的基本使用

# 创建变量(赋值)
name = "张三"
age = 20
height = 1.75

# 使用变量
print(name)  # 张三
print(age)   # 20

# 变量可以改变
age = 21
print(age)  # 21

# 变量可以参与运算
next_year_age = age + 1
print(next_year_age)  # 22

标识符就是我们给变量、函数、类等起的名字。Python对标识符有严格的规定:

标识符的规则

  1. 字符范围:只能由 字母(a-z/A-Z)、数字(0-9)、下划线(_) 组成,且不能以数字开头
    正确:nameuser_age_scoreBook123
    错误:123name(数字开头)、user-age(含连字符)、my name(含空格)、价格(非ASCII字符,不推荐)

  2. 大小写敏感Namename 是两个完全不同的变量。

    Name = "张三"
    name = "李四"
    print(Name)  # 输出:张三
    print(name)  # 输出:李四
    
  3. 不能使用关键字:不能使用Python内置的关键字(保留字)作为变量/函数名,比如 ifelseforwhiledefclass 等。
    可通过以下代码查看所有关键字:

    import keyword
    print(keyword.kwlist)  # 输出Python所有保留字
    

命名建议

  • 用有意义的名字:student_countsc好理解
  • 多个单词用下划线连接:user_name(Python推荐)
  • 常量用大写:PI = 3.14159
  • 私有变量用下划线开头:_internal_value

多个变量赋值

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

# 交换两个变量的值(这个太方便了!)
a = 10
b = 20
a, b = b, a  # 不需要临时变量
print(a, b)  # 20 10

# 给多个变量赋相同的值
x = y = z = 0
print(x, y, z)  # 0 0 0

四、数据类型

Python有很多种数据类型,每种类型能做的事情不一样。

基本数据类型

# 数字类型
integer = 10           # int - 整数
floating = 3.14        # float - 浮点数(小数)
complex_num = 3 + 4j   # complex - 复数

# 文本类型
text = "Hello"         # str - 字符串

# 布尔类型
is_true = True         # bool - 布尔值
is_false = False

# 序列类型
my_list = [1, 2, 3]           # list - 列表(可变)
my_tuple = (1, 2, 3)          # tuple - 元组(不可变)
my_range = range(5)           # range - 范围

# 映射类型
my_dict = {"name": "张三"}    # dict - 字典

# 集合类型
my_set = {1, 2, 3}            # set - 集合

# 空值类型
nothing = None                # NoneType - 空值

整数(int)

# 整数可以是正数、负数、零
positive = 100
negative = -50
zero = 0

# Python的整数没有大小限制!
huge = 123456789012345678901234567890
print(huge)  # 完全没问题

# 不同进制的整数
binary = 0b1010      # 二进制,等于10
octal = 0o12         # 八进制,等于10
hexadecimal = 0xA    # 十六进制,等于10

print(binary, octal, hexadecimal)  # 10 10 10

浮点数(float)

# 小数
price = 19.99
pi = 3.14159

# 科学计数法
large = 1.5e3   # 1.5 × 10³ = 1500.0
small = 1.5e-3  # 1.5 × 10⁻³ = 0.0015

print(large, small)  # 1500.0 0.0015

# 浮点数的精度问题(这个坑我踩过)
print(0.1 + 0.2)  # 0.30000000000000004(不是0.3!)

# 解决方法:四舍五入
result = round(0.1 + 0.2, 2)  # 保留2位小数
print(result)  # 0.3

字符串(str)

# 单引号和双引号都可以
name1 = 'Alice'
name2 = "Bob"

# 字符串里有引号怎么办?
sentence1 = "He said 'Hello'"  # 外面用双引号
sentence2 = 'She said "Hi"'    # 外面用单引号
sentence3 = "He said \"Hello\""  # 用转义字符

# 多行字符串
poem = """床前明月光,
疑是地上霜。
举头望明月,
低头思故乡。"""
print(poem)

# 原始字符串(不转义)
path = r"C:\Users\name\Documents"  # r前缀
print(path)  # 反斜杠不会被转义

布尔值(bool)

# 只有两个值
is_student = True
is_teacher = False

# 比较运算返回布尔值
print(5 > 3)   # True
print(5 < 3)   # False
print(5 == 5)  # True

# 逻辑运算
print(True and False)  # False
print(True or False)   # True
print(not True)        # False

# 哪些值会被当作False?
print(bool(0))         # False
print(bool(""))        # False(空字符串)
print(bool([]))        # False(空列表)
print(bool(None))      # False

# 其他都是True
print(bool(1))         # True
print(bool("hello"))   # True
print(bool([1, 2]))    # True

列表(list)

# 创建列表
fruits = ["苹果", "香蕉", "橙子"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True]  # 可以混合类型

# 访问元素(索引从0开始)
print(fruits[0])   # 苹果
print(fruits[1])   # 香蕉
print(fruits[-1])  # 橙子(负数从后往前数)

# 修改元素
fruits[0] = "西瓜"
print(fruits)  # ['西瓜', '香蕉', '橙子']

# 列表的长度
print(len(fruits))  # 3

元组(tuple)

# 元组和列表很像,但不能修改
point = (3, 5)
person = ("张三", 18, "学生")

# 访问元素
print(point[0])  # 3

# 不能修改
# point[0] = 10  # 报错!TypeError

# 单个元素的元组要加逗号
single = (5,)  # 注意这个逗号
print(type(single))  # <class 'tuple'>

not_tuple = (5)  # 这不是元组,只是数字5
print(type(not_tuple))  # <class 'int'>

字典(dict)

# 字典是键值对
student = {
    "name": "小明",
    "age": 18,
    "grade": "高三"
}

# 访问值
print(student["name"])  # 小明
print(student["age"])   # 18

# 修改值
student["age"] = 19

# 添加新键值对
student["school"] = "一中"

# 删除键值对
del student["grade"]

print(student)

集合(set)

# 集合是不重复的元素
numbers = {1, 2, 3, 4, 5}
fruits = {"苹果", "香蕉", "橙子"}

# 自动去重
nums = {1, 2, 2, 3, 3, 3}
print(nums)  # {1, 2, 3}

# 集合运算
a = {1, 2, 3}
b = {3, 4, 5}

print(a | b)  # {1, 2, 3, 4, 5} 并集
print(a & b)  # {3} 交集
print(a - b)  # {1, 2} 差集

五、type()语句

type()函数可以告诉你一个变量是什么类型,这在调试时能起到关键作用。

# 查看各种类型
print(type(123))           # <class 'int'>
print(type(3.14))          # <class 'float'>
print(type("hello"))       # <class 'str'>
print(type(True))          # <class 'bool'>
print(type([1, 2, 3]))     # <class 'list'>
print(type((1, 2, 3)))     # <class 'tuple'>
print(type({"a": 1}))      # <class 'dict'>
print(type({1, 2, 3}))     # <class 'set'>
print(type(None))          # <class 'NoneType'>

让我们来看看如何实际应用的:

# 实际应用
def process_data(data):
    print(f"数据类型:{type(data)}")
    if type(data) == int:
        print("这是整数")
    elif type(data) == str:
        print("这是字符串")

process_data(100)      # 数据类型:<class 'int'> 这是整数
process_data("hello")  # 数据类型:<class 'str'> 这是字符串

# 更好的方法:用isinstance()
print(isinstance(123, int))     # True
print(isinstance("hi", str))    # True
print(isinstance([1, 2], list)) # True

六、类型转换

有时候需要把一种类型转换成另一种类型,比如把字符串转成数字。

转换成整数 - int()

# 字符串转整数
age_str = "18"
age = int(age_str)
print(age + 2)  # 20

# 浮点数转整数(会丢失小数部分)
pi = 3.14
pi_int = int(pi)
print(pi_int)  # 3

# 布尔值转整数
print(int(True))   # 1
print(int(False))  # 0

# 不能转换的情况
# int("hello")  # 报错!ValueError
# int("3.14")   # 报错!不能直接转,要先转成float

转换成浮点数 - float()

# 字符串转浮点数
price_str = "19.99"
price = float(price_str)
print(price)  # 19.99

# 整数转浮点数
num = 10
num_float = float(num)
print(num_float)  # 10.0

# 布尔值转浮点数
print(float(True))   # 1.0
print(float(False))  # 0.0

转换成字符串 - str()

# 数字转字符串
age = 18
age_str = str(age)
print("我今年" + age_str + "岁")  # 我今年18岁

# 任何类型都能转成字符串
print(str(3.14))        # "3.14"
print(str(True))        # "True"
print(str([1, 2, 3]))   # "[1, 2, 3]"
print(str({"a": 1}))    # "{'a': 1}"

转换成布尔值 - bool()

# 数字转布尔值
print(bool(0))    # False
print(bool(1))    # True
print(bool(-5))   # True(非零都是True)

# 字符串转布尔值
print(bool(""))       # False(空字符串)
print(bool("hello"))  # True

# 列表转布尔值
print(bool([]))       # False(空列表)
print(bool([1, 2]))   # True

# None转布尔值
print(bool(None))     # False

转换成列表、元组、集合

# 字符串转列表
text = "hello"
chars = list(text)
print(chars)  # ['h', 'e', 'l', 'l', 'o']

# 元组转列表
t = (1, 2, 3)
l = list(t)
print(l)  # [1, 2, 3]

# 列表转元组
l = [1, 2, 3]
t = tuple(l)
print(t)  # (1, 2, 3)

# 列表转集合(自动去重)
l = [1, 2, 2, 3, 3, 3]
s = set(l)
print(s)  # {1, 2, 3}

# 集合转列表
s = {3, 1, 2}
l = list(s)
print(l)  # [1, 2, 3](集合会自动排序)

八、运算符

运算符就是用来做运算的符号,Python有很多种运算符。

算术运算符

a = 10
b = 3

print(a + b)   # 13  加法
print(a - b)   # 7   减法
print(a * b)   # 30  乘法
print(a / b)   # 3.333... 除法(结果是浮点数)
print(a // b)  # 3   整除(只要整数部分)
print(a % b)   # 1   取余数(模运算)
print(a ** b)  # 1000 幂运算(10的3次方)

比较运算符

a = 10
b = 5

print(a == b)  # False  等于
print(a != b)  # True   不等于
print(a > b)   # True   大于
print(a < b)   # False  小于
print(a >= b)  # True   大于等于
print(a <= b)  # False  小于等于

# 字符串也可以比较
print("abc" < "abd")  # True(按字典序)
print("apple" == "apple")  # True

# 链式比较(Python特有)
x = 5
print(1 < x < 10)  # True(相当于 1 < x and x < 10)
print(10 < x < 20)  # False

赋值运算符

# 基本赋值
x = 10

# 复合赋值
x += 5   # 相当于 x = x + 5
print(x)  # 15

x -= 3   # 相当于 x = x - 3
print(x)  # 12

x *= 2   # 相当于 x = x * 2
print(x)  # 24

x /= 4   # 相当于 x = x / 4
print(x)  # 6.0

x //= 2  # 相当于 x = x // 2
print(x)  # 3.0

x %= 2   # 相当于 x = x % 2
print(x)  # 1.0

x **= 3  # 相当于 x = x ** 3
print(x)  # 1.0

逻辑运算符

# and:都为真才为真
print(True and True)    # True
print(True and False)   # False
print(False and False)  # False

# or:有一个真就为真
print(True or False)   # True
print(False or False)  # False

# not:取反
print(not True)   # False
print(not False)  # True

# 实际应用
age = 20
has_id = True

if age >= 18 and has_id:
    print("可以进入")  # 输出这个
else:
    print("不能进入")

# 短路运算
x = 0
y = 10
result = x and y  # x是0(False),不会再看y
print(result)  # 0

result = x or y  # x是0(False),会看y
print(result)  # 10

成员运算符

# in:检查是否在序列中
fruits = ["苹果", "香蕉", "橙子"]
print("苹果" in fruits)  # True
print("西瓜" in fruits)  # False

# not in:检查是否不在序列中
print("西瓜" not in fruits)  # True

# 字符串中也可以用
text = "Hello World"
print("Hello" in text)  # True
print("Python" in text)  # False

# 字典中检查键
student = {"name": "张三", "age": 18}
print("name" in student)  # True
print("grade" in student)  # False

身份运算符

# is:检查是否是同一个对象
a = [1, 2, 3]
b = [1, 2, 3]
c = a

print(a == b)  # True(值相同)
print(a is b)  # False(不是同一个对象)
print(a is c)  # True(是同一个对象)

# is not
print(a is not b)  # True

# None的检查要用is
x = None
print(x is None)  # True(推荐)
print(x == None)  # True(不推荐)

运算符优先级

# 从高到低:
# 1. **(幂运算)
# 2. *, /, //, %(乘除)
# 3. +, -(加减)
# 4. ==, !=, >, <, >=, <=(比较)
# 5. not
# 6. and
# 7. or

# 示例
result = 2 + 3 * 4
print(result)  # 14(先乘后加)

result = (2 + 3) * 4
print(result)  # 20(括号优先)

result = 10 > 5 and 20 < 30
print(result)  # True

# 复杂表达式建议加括号
result = ((10 + 5) * 2) > (20 - 5)
print(result)  # True

九、字符串

字符串是我用得最多的类型之一,Python的字符串功能非常强大。

字符串的创建

# 单引号
name1 = 'Alice'

# 双引号
name2 = "Bob"

# 三引号(多行)
poem = """床前明月光,
疑是地上霜。
举头望明月,
低头思故乡。"""

# 转义字符
text = "第一行\n第二行"  # \n是换行
print(text)

path = "C:\\Users\\name"  # \\是反斜杠
print(path)

quote = "He said \"Hello\""  # \"是双引号
print(quote)

# 原始字符串(不转义)
path = R"C:\Users\name\Documents"
print(path)  # 反斜杠不会被转义

字符串拼接

# 1. 使用 + 运算符(适合少量短字符串拼接)
str1 = "Hello"
str2 = "World"
result1 = str1 + " " + str2
print(result1)  # 输出: Hello World

# 2. 使用 str.join() 方法(适合大量字符串拼接,性能最优)
parts = ["Hello", "World", "from", "Python"]
result2 = " ".join(parts)
print(result2)  # 输出: Hello World from Python

# 3. 使用 f-string (Python 3.6 推荐)
name = "Alice"
age = 25
result3 = f"Name: {name}, Age: {age}"
print(result3)  # 输出: Name: Alice, Age: 25

# 4. 使用 str.format() 方法
result4 = "Name: {}, Age: {}".format(name, age)
print(result4)  # 输出: Name: Alice, Age: 25

# 5. 使用 % 格式化(旧式,不推荐但仍兼容)
result5 = "Name: %s, Age: %d" % (name, age)
print(result5)  # 输出: Name: Alice, Age: 25

# 6. 多行字符串字面量自动拼接(无需运算符)
result6 = ("Hello "
           "World "
           "Auto")
print(result6)  # 输出: Hello World Auto



# 错误1:字符串与非字符串类型直接 +
try:
    result = "Age: " + 25  # 25是int,不能直接和str拼接
except TypeError as e:
    print(f"错误1: {e}")  # 输出: 错误1: can only concatenate str (not "int") to str

# 错误2:误用逗号拼接(得到的是元组,不是字符串)
result = "Hello", "World"
print(f"错误2: {result}, 类型: {type(result)}")  # 输出: 错误2: ('Hello', 'World'), 类型: <class 'tuple'>

# 错误3:尝试通过索引修改字符串(Python字符串不可变)
try:
    s = "Hello"
    s[0] = "h"  # 不可变对象不支持元素赋值
except TypeError as e:
    print(f"错误3: {e}")  # 输出: 错误3: 'str' object does not support item assignment

# 错误4:join() 传入包含非字符串元素的可迭代对象
try:
    parts = ["Hello", 25, "World"]
    result = " ".join(parts)  # 25是int,join要求所有元素都是str
except TypeError as e:
    print(f"错误4: {e}")  # 输出: 错误4: sequence item 1: expected str instance, int found

# 错误5:join() 传入非可迭代对象
try:
    result = " ".join("Hello")  # 虽然字符串是可迭代的,但这会拆成字符,不是预期拼接;若传入数字会报错
    # 更典型错误: " ".join(123)
    result = " ".join(123)
except TypeError as e:
    print(f"错误5: {e}")  # 输出: 错误5: can only join an iterable

字符串的索引和切片

text = "Python"

# 索引(从0开始)
print(text[0])   # P
print(text[1])   # y
print(text[-1])  # n(最后一个)
print(text[-2])  # o(倒数第二个)

# 切片 [start:end:step]
print(text[0:3])   # Pyt(索引0到2)
print(text[:3])    # Pyt(省略start从头开始)
print(text[3:])    # hon(省略end到最后)
print(text[::2])   # Pto(步长为2)
print(text[::-1])  # nohtyP(反转字符串)

# 实际应用:提取文件扩展名
filename = "document.pdf"
extension = filename[-3:]
print(extension)  # pdf

# 实际应用:隐藏手机号中间4位
phone = "13812345678"
hidden = phone[:3] + "****" + phone[7:]
print(hidden)  # 138****5678

字符串的格式化

# 方法1:%格式化(老方法)
name = "张三"
age = 18
print("我叫%s,今年%d岁" % (name, age))

# 方法2:format()方法
print("我叫{},今年{}岁".format(name, age))
print("我叫{0},今年{1}岁,{0}很高兴认识你".format(name, age))
print("我叫{name},今年{age}岁".format(name=name, age=age))

# 方法3:f-string(推荐,Python 3.6+)
print(f"我叫{name},今年{age}岁")
print(f"明年我{age + 1}岁")  # 可以包含表达式

字符串格式化的精度控制

浮点数精度控制

# 方法1:% 格式化
pi = 3.141592653589793

# %f 默认保留6位小数
print("默认精度: %f" % pi)  # 输出: 默认精度: 3.141593

# %.2f 保留2位小数
print("保留2位: %.2f" % pi)  # 输出: 保留2位: 3.14

# %10.2f 总宽度10,保留2位小数,右对齐
print("宽度控制: %10.2f" % pi)  # 输出: 宽度控制:       3.14

# %-10.2f 左对齐
print("左对齐: %-10.2f元" % pi)  # 输出: 左对齐: 3.14      元


# 方法2:format() 方法
price = 1234.5678

# {:.2f} 保留2位小数
print("价格: {:.2f}元".format(price))  # 输出: 价格: 1234.57元

# {:10.2f} 总宽度10,保留2位小数
print("对齐: {:10.2f}".format(price))  # 输出: 对齐:    1234.57

# {:0>10.2f} 用0填充,右对齐
print("填充0: {:0>10.2f}".format(price))  # 输出: 填充0: 0001234.57

# {:<10.2f} 左对齐
print("左对齐: {:<10.2f}".format(price))  # 输出: 左对齐: 1234.57   

# {:^10.2f} 居中对齐
print("居中: {:^10.2f}".format(price))  # 输出: 居中:  1234.57  

# {:,} 千位分隔符
print("分隔符: {:,.2f}".format(price))  # 输出: 分隔符: 1,234.57


# 方法3:f-string
score = 87.6543

# 基本精度控制
print(f"成绩: {score:.2f}分")  # 输出: 成绩: 87.65分

# 百分比格式
ratio = 0.8765
print(f"完成率: {ratio:.2%}")  # 输出: 完成率: 87.65%

# 科学计数法
big_num = 123456789.123
print(f"科学计数: {big_num:.2e}")  # 输出: 科学计数: 1.23e+08

# 组合使用:宽度+精度+对齐
print(f"复杂格式: {score:>10.3f}")  # 输出: 复杂格式:     87.654

整数格式化

num = 42

# 进制转换
print(f"十进制: {num:d}")    # 输出: 十进制: 42
print(f"二进制: {num:b}")    # 输出: 二进制: 101010
print(f"八进制: {num:o}")    # 输出: 八进制: 52
print(f"十六进制: {num:x}")  # 输出: 十六进制: 2a
print(f"十六进制(大写): {num:X}")  # 输出: 十六进制(大写): 2A

# 带前缀的进制表示
print(f"二进制带前缀: {num:#b}")    # 输出: 二进制带前缀: 0b101010
print(f"十六进制带前缀: {num:#x}")  # 输出: 十六进制带前缀: 0x2a

# 补零和对齐=
order_id = 7
print(f"订单号: {order_id:0>5d}")  # 输出: 订单号: 00007

# 千位分隔符(适合大数字)
population = 1400000000
print(f"人口: {population:,}")  # 输出: 人口: 1,400,000,000

格式化规范表:

格式符号 含义 示例 输出
:.2f 保留2位小数 f"{3.14159:.2f}" 3.14
:10.2f 宽度10,保留2位小数 f"{3.14:10.2f}" 3.14
:<10 左对齐,宽度10 f"{'hi':<10}" hi
:>10 右对齐,宽度10 f"{'hi':>10}" hi
:^10 居中,宽度10 f"{'hi':^10}" hi
:0>5 用0填充,宽度5 f"{42:0>5}" 00042
:, 千位分隔符 f"{1234567:,}" 1,234,567
:.2% 百分比,保留2位 f"{0.875:.2%}" 87.50%
:.2e 科学计数法 f"{1234:.2e}" 1.23e+03
:#x 十六进制带前缀 f"{255:#x}" 0xff

表达式的格式化

表达式格式化让字符串不再是静态的文本,而是可以包含动态计算的数据。类似于嵌入了一个微型计算器,随时可以进行运算。

#基础算术表达式
a = 10
b = 3

print(f"{a} + {b} = {a + b}")      # 输出: 10 + 3 = 13
print(f"{a} - {b} = {a - b}")      # 输出: 10 - 3 = 7
print(f"{a} * {b} = {a * b}")      # 输出: 10 * 3 = 30
print(f"{a} / {b} = {a / b:.2f}")  # 输出: 10 / 3 = 3.33
print(f"{a} // {b} = {a // b}")    # 输出: 10 // 3 = 3
print(f"{a} % {b} = {a % b}")      # 输出: 10 % 3 = 1
print(f"{a} ** {b} = {a ** b}")    # 输出: 10 ** 3 = 1000


# 条件表达式(三元运算符)
age = 17
status = f"你{'已成年' if age >= 18 else '未成年'}"
print(status)  # 输出: 你未成年

score = 85
grade = f"等级: {'优秀' if score >= 90 else '良好' if score >= 80 else '及格' if score >= 60 else '不及格'}"
print(grade)  # 输出: 等级: 良好

# 函数调用
name = "  alice  "
print(f"原始: '{name}'")                    # 输出: 原始: '  alice  '
print(f"去空格: '{name.strip()}'")          # 输出: 去空格: 'alice'
print(f"大写: '{name.strip().upper()}'")    # 输出: 大写: 'ALICE'
print(f"首字母大写: '{name.strip().title()}'")  # 输出: 首字母大写: 'Alice'

# 使用内置函数
numbers = [1, 2, 3, 4, 5]
print(f"列表: {numbers}")           # 输出: 列表: [1, 2, 3, 4, 5]
print(f"长度: {len(numbers)}")      # 输出: 长度: 5
print(f"总和: {sum(numbers)}")      # 输出: 总和: 15
print(f"最大值: {max(numbers)}")    # 输出: 最大值: 5
print(f"平均值: {sum(numbers)/len(numbers):.2f}")  # 输出: 平均值: 3.00



十、数据输入

input()函数的基础用法

# ============ 基本输入 ============
# input()总是返回字符串类型
name = input("请输入你的名字: ")
print(f"你好,{name}!")

# 输入提示可以包含任何文本
age = input("请输入你的年龄: ")
print(f"你输入的年龄是: {age},类型是: {type(age)}")  # 类型是 <class 'str'>


# ============ 类型转换:将字符串转为数字 ============
# 转换为整数
age_str = input("请输入你的年龄: ")
age_int = int(age_str)  # 字符串转整数
print(f"明年你将{age_int + 1}岁")

# 转换为浮点数
height_str = input("请输入你的身高(米): ")
height_float = float(height_str)
print(f"你的身高是{height_float}米,即{height_float * 100}厘米")

# 简化写法:直接在input外层转换
weight = float(input("请输入你的体重(kg): "))
bmi = weight / (height_float ** 2)
print(f"你的BMI指数是: {bmi:.2f}")


# ============ 输入多个值 ============
# 方法1:分别输入
print("请输入两个数字:")
num1 = int(input("第一个数: "))
num2 = int(input("第二个数: "))
print(f"{num1} + {num2} = {num1 + num2}")

# 方法2:一行输入,用空格分隔
print("请输入两个数字(用空格分隔): ")
numbers = input().split()  # split()默认按空格分割,返回列表
num1 = int(numbers[0])
num2 = int(numbers[1])
print(f"{num1} * {num2} = {num1 * num2}")

# 方法3:使用解包(更优雅)
print("请输入三个数字(用空格分隔): ")
a, b, c = input().split()
a, b, c = int(a), int(b), int(c)
print(f"三个数的和: {a + b + c}")

# 方法4:使用map()函数(最简洁)
print("请输入三个数字(用空格分隔): ")
x, y, z = map(int, input().split())
print(f"三个数的积: {x * y * z}")

十一、条件判断

if语句的基本结构

# 最简单的if语句
age = 20
if age >= 18:
    print("你已经成年了")
    print("可以独立做决定")

# 注意:Python用缩进来表示代码块,不是用大括号
# 缩进通常是4个空格(按Tab键)

# if语句的判断条件
score = 85
if score >= 60:
    print("及格了!")

# 条件可以是任何返回布尔值的表达式
name = "张三"
if name == "张三":
    print("找到张三了")

# 条件可以是变量本身
has_ticket = True
if has_ticket:
    print("可以进场")

# 空列表、空字符串、0、None都会被当作False
items = []
if items:
    print("有物品")
else:
    print("没有物品")  # 会执行这个

if-else语句

# if-else:二选一
age = 16
if age >= 18:
    print("成年人,可以看这部电影")
else:
    print("未成年,不能观看")

# 实际应用:判断奇偶数
number = 7
if number % 2 == 0:
    print(f"{number}是偶数")
else:
    print(f"{number}是奇数")

# 实际应用:登录验证
username = input("请输入用户名: ")
password = input("请输入密码: ")

if username == "admin" and password == "123456":
    print("登录成功!")
else:
    print("用户名或密码错误")

# 可以在条件中使用复杂表达式
temperature = 28
humidity = 70

if temperature > 30 and humidity > 80:
    print("又热又潮湿,开空调吧")
else:
    print("天气还不错")

if-elif-else语句

# elif:多个条件判断(相当于else if)
score = 85

if score >= 90:
    print("优秀")
elif score >= 80:
    print("良好")
elif score >= 70:
    print("中等")
elif score >= 60:
    print("及格")
else:
    print("不及格")

# 实际应用:根据时间问候
hour = 14

if hour < 6:
    print("凌晨好,夜猫子")
elif hour < 9:
    print("早上好")
elif hour < 12:
    print("上午好")
elif hour < 14:
    print("中午好")
elif hour < 18:
    print("下午好")
elif hour < 22:
    print("晚上好")
else:
    print("夜深了,该休息了")

# 实际应用:BMI计算
weight = 70  # kg
height = 1.75  # m
bmi = weight / (height ** 2)

if bmi < 18.5:
    print(f"BMI: {bmi:.1f} - 偏瘦")
elif bmi < 24:
    print(f"BMI: {bmi:.1f} - 正常")
elif bmi < 28:
    print(f"BMI: {bmi:.1f} - 偏胖")
else:
    print(f"BMI: {bmi:.1f} - 肥胖")

嵌套if语句

# if语句可以嵌套使用
age = 20
has_ticket = True
has_id = True

if age >= 18:
    print("年龄符合要求")
    if has_ticket:
        print("有票")
        if has_id:
            print("有身份证")
            print("可以入场!")
        else:
            print("请出示身份证")
    else:
        print("请先购票")
else:
    print("未成年不能入场")

# 实际应用:用户权限检查
is_logged_in = True
is_admin = False
is_vip = True

if is_logged_in:
    print("已登录")
    if is_admin:
        print("管理员权限:可以访问所有功能")
    elif is_vip:
        print("VIP用户:可以访问高级功能")
    else:
        print("普通用户:可以访问基础功能")
else:
    print("请先登录")

# 嵌套太深不好,可以用逻辑运算符简化
if is_logged_in and is_admin:
    print("管理员已登录")
elif is_logged_in and is_vip:
    print("VIP用户已登录")
elif is_logged_in:
    print("普通用户已登录")
else:
    print("未登录")

条件表达式(三元运算符)

# Python的三元运算符:value_if_true if condition else value_if_false
age = 20
status = "成年" if age >= 18 else "未成年"
print(status)  # 成年

# 等价于:
if age >= 18:
    status = "成年"
else:
    status = "未成年"

# 实际应用:取绝对值
number = -5
abs_value = number if number >= 0 else -number
print(abs_value)  # 5

# 实际应用:设置默认值
username = input("请输入用户名(直接回车使用默认): ")
username = username if username else "游客"
print(f"欢迎,{username}")

# 可以嵌套使用(但不要太复杂)
score = 85
grade = "优秀" if score >= 90 else "良好" if score >= 80 else "及格" if score >= 60 else "不及格"
print(grade)  # 良好

条件判断的常见技巧

# 1. 判断是否在范围内
age = 25
if 18 <= age <= 65:
    print("工作年龄段")

# 2. 判断是否在列表中
fruit = "苹果"
fruits = ["苹果", "香蕉", "橙子"]
if fruit in fruits:
    print(f"{fruit}在列表中")

# 3. 判断字符串是否为空
name = ""
if not name:  # 空字符串是False
    print("名字不能为空")

# 4. 判断多个条件中的任意一个
day = "周六"
if day in ["周六", "周日"]:
    print("周末,休息")

# 5. 使用any()和all()
scores = [85, 90, 78, 92]
if all(score >= 60 for score in scores):
    print("所有科目都及格")

if any(score >= 90 for score in scores):
    print("至少有一门优秀")

# 6. 避免重复判断
# 不好的写法
x = 10
if x > 5:
    if x < 15:
        print("x在5到15之间")

# 好的写法
if 5 < x < 15:
    print("x在5到15之间")

条件判断的常见错误

# 错误1:使用=而不是==
x = 5
# if x = 5:  # 语法错误!= 是赋值,== 是比较
if x == 5:  # 正确
    print("x等于5")

# 错误2:忘记冒号
# if x > 0  # 语法错误!缺少冒号
if x > 0:  # 正确
    print("x是正数")

# 错误3:缩进错误
if x > 0:
    print("这行正确缩进")
# print("这行没有缩进,不属于if块")

# 错误4:比较浮点数相等
a = 0.1 + 0.2
# if a == 0.3:  # 可能不成立,因为浮点数精度问题
if abs(a - 0.3) < 0.0001:  # 正确做法
    print("a约等于0.3")

# 错误5:混淆and和or
age = 25
# if age > 18 or age < 65:  # 错误!这个条件永远为真
if age > 18 and age < 65:  # 正确
    print("工作年龄")

十二、循环语句

循环就像是让计算机重复做某件事,直到满足某个条件为止。Python有两种主要的循环:for循环和while循环。

for循环的基本用法

# 最基本的for循环:遍历列表
fruits = ["苹果", "香蕉", "橙子"]
for fruit in fruits:
    print(fruit)
# 输出:
# 苹果
# 香蕉
# 橙子

# 遍历字符串(字符串也是可迭代对象)
for char in "Python":
    print(char)
# 输出:P y t h o n(每个字母一行)

# 遍历字典
student = {"name": "张三", "age": 18, "grade": "高三"}

# 遍历键
for key in student:
    print(key)
# 输出:name age grade

# 遍历值
for value in student.values():
    print(value)
# 输出:张三 18 高三

# 同时遍历键和值
for key, value in student.items():
    print(f"{key}: {value}")
# 输出:
# name: 张三
# age: 18
# grade: 高三

# 遍历集合
numbers = {1, 2, 3, 4, 5}
for num in numbers:
    print(num)

range()函数

# range()生成数字序列,常用于for循环
# range(stop):从0到stop-1
for i in range(5):
    print(i)
# 输出:0 1 2 3 4

# range(start, stop):从start到stop-1
for i in range(1, 6):
    print(i)
# 输出:1 2 3 4 5

# range(start, stop, step):指定步长
for i in range(0, 10, 2):
    print(i)
# 输出:0 2 4 6 8

# 倒序
for i in range(10, 0, -1):
    print(i)
# 输出:10 9 8 7 6 5 4 3 2 1

# 实际应用:打印乘法表
for i in range(1, 10):
    for j in range(1, i + 1):
        print(f"{j}×{i}={i*j}", end="\t")
    print()  # 换行

# 实际应用:计算1到100的和
total = 0
for i in range(1, 101):
    total += i
print(f"1到100的和是: {total}")  # 5050

# 实际应用:找出1到100的所有偶数
evens = []
for i in range(1, 101):
    if i % 2 == 0:
        evens.append(i)
print(f"偶数有: {evens}")

enumerate()函数

# enumerate()可以同时获取索引和值
fruits = ["苹果", "香蕉", "橙子"]

# 不使用enumerate
for i in range(len(fruits)):
    print(f"{i}: {fruits[i]}")

# 使用enumerate(更优雅)
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")
# 输出:
# 0: 苹果
# 1: 香蕉
# 2: 橙子

# 指定起始索引
for index, fruit in enumerate(fruits, start=1):
    print(f"{index}. {fruit}")
# 输出:
# 1. 苹果
# 2. 香蕉
# 3. 橙子

# 实际应用:给列表元素编号
students = ["张三", "李四", "王五"]
for num, name in enumerate(students, start=1):
    print(f"学号{num}: {name}")

zip()函数

# zip()可以同时遍历多个序列
names = ["张三", "李四", "王五"]
ages = [18, 19, 20]
grades = ["高一", "高二", "高三"]

for name, age, grade in zip(names, ages, grades):
    print(f"{name}{age}岁,{grade}")
# 输出:
# 张三,18岁,高一
# 李四,19岁,高二
# 王五,20岁,高三

# 长度不同时,以最短的为准
list1 = [1, 2, 3, 4, 5]
list2 = ['a', 'b', 'c']
for num, letter in zip(list1, list2):
    print(f"{num}-{letter}")
# 输出:
# 1-a
# 2-b
# 3-c

# 实际应用:创建字典
keys = ["name", "age", "city"]
values = ["张三", 25, "北京"]
person = dict(zip(keys, values))
print(person)  # {'name': '张三', 'age': 25, 'city': '北京'}

while循环

# while循环:只要条件为真就一直执行
count = 0
while count < 5:
    print(f"count = {count}")
    count += 1
# 输出:count = 0 到 count = 4

# 实际应用:猜数字游戏
import random
secret = random.randint(1, 100)
guess = 0
attempts = 0

while guess != secret:
    guess = int(input("猜一个1到100的数字: "))
    attempts += 1
    if guess < secret:
        print("太小了")
    elif guess > secret:
        print("太大了")
    else:
        print(f"恭喜你猜对了!用了{attempts}次")

# 实际应用:输入验证
password = ""
while len(password) < 6:
    password = input("请输入密码(至少6位): ")
    if len(password) < 6:
        print("密码太短,请重新输入")
print("密码设置成功")

# 实际应用:菜单循环
while True:
    print("\n=== 菜单 ===")
    print("1. 查看信息")
    print("2. 修改信息")
    print("3. 退出")
    choice = input("请选择: ")
    
    if choice == "1":
        print("查看信息...")
    elif choice == "2":
        print("修改信息...")
    elif choice == "3":
        print("再见!")
        break  # 跳出循环
    else:
        print("无效选择,请重新输入")

break和continue

# break:立即跳出循环
for i in range(10):
    if i == 5:
        break  # 遇到5就停止
    print(i)
# 输出:0 1 2 3 4

# continue:跳过本次循环,继续下一次
for i in range(10):
    if i % 2 == 0:
        continue  # 跳过偶数
    print(i)
# 输出:1 3 5 7 9

# 实际应用:查找第一个符合条件的元素
numbers = [1, 3, 5, 8, 10, 12]
for num in numbers:
    if num % 2 == 0:
        print(f"找到第一个偶数: {num}")
        break

# 实际应用:跳过特定条件
scores = [85, -1, 90, -1, 78, 92]  # -1表示缺考
total = 0
count = 0
for score in scores:
    if score == -1:
        continue  # 跳过缺考
    total += score
    count += 1
average = total / count
print(f"平均分: {average:.2f}")

# break和continue在while循环中
count = 0
while True:
    count += 1
    if count % 2 == 0:
        continue  # 跳过偶数
    print(count)
    if count >= 10:
        break  # 到10就停止

else子句

# for和while循环都可以有else子句
# 正常结束循环时执行else,被break打断则不执行

# 示例1:查找元素
numbers = [1, 3, 5, 7, 9]
target = 6

for num in numbers:
    if num == target:
        print(f"找到了{target}")
        break
else:
    print(f"没找到{target}")  # 会执行这个

# 示例2:验证所有元素
scores = [85, 90, 78, 92, 88]
for score in scores:
    if score < 60:
        print("有人不及格")
        break
else:
    print("全部及格")  # 会执行这个

# while循环的else
count = 0
while count < 5:
    print(count)
    count += 1
else:
    print("循环正常结束")  # 会执行

# 被break打断的情况
count = 0
while count < 10:
    if count == 5:
        break
    count += 1
else:
    print("这不会执行")  # 不会执行

嵌套循环

# 循环可以嵌套使用
# 打印矩形
for i in range(3):
    for j in range(5):
        print("*", end="")
    print()  # 换行
# 输出:
# *****
# *****
# *****

# 打印三角形
for i in range(1, 6):
    for j in range(i):
        print("*", end="")
    print()
# 输出:
# *
# **
# ***
# ****
# *****

# 实际应用:遍历二维列表
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

for row in matrix:
    for num in row:
        print(num, end=" ")
    print()

# 实际应用:找出所有两位数中能被7整除的数
for i in range(10, 100):
    if i % 7 == 0:
        print(i, end=" ")
print()

# 实际应用:生成所有两位数的组合
for i in range(1, 10):
    for j in range(0, 10):
        print(f"{i}{j}", end=" ")
    print()

列表推导式

# 列表推导式:用一行代码创建列表
# 基本语法:[expression for item in iterable]

# 传统方法
squares = []
for i in range(10):
    squares.append(i ** 2)
print(squares)

# 列表推导式(更简洁)
squares = [i ** 2 for i in range(10)]
print(squares)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 带条件的列表推导式
# [expression for item in iterable if condition]
evens = [i for i in range(20) if i % 2 == 0]
print(evens)  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# 实际应用:提取字符串中的数字
text = "abc123def456"
digits = [char for char in text if char.isdigit()]
print(digits)  # ['1', '2', '3', '4', '5', '6']

# 实际应用:转换列表元素
names = ["alice", "bob", "charlie"]
upper_names = [name.upper() for name in names]
print(upper_names)  # ['ALICE', 'BOB', 'CHARLIE']

# 嵌套列表推导式
matrix = [[i * j for j in range(1, 4)] for i in range(1, 4)]
print(matrix)  # [[1, 2, 3], [2, 4, 6], [3, 6, 9]]

# 字典推导式
squares_dict = {i: i ** 2 for i in range(5)}
print(squares_dict)  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

# 集合推导式
unique_chars = {char.lower() for char in "Hello World"}
print(unique_chars)  # {'h', 'e', 'l', 'o', 'w', 'r', 'd', ' '}

循环的性能优化技巧

# 1. 避免在循环中重复计算
# 不好的写法
total = 0
for i in range(1000):
    total += len([1, 2, 3, 4, 5])  # 每次都计算长度

# 好的写法
total = 0
length = len([1, 2, 3, 4, 5])  # 只计算一次
for i in range(1000):
    total += length

# 2. 使用生成器表达式节省内存
# 列表推导式(占用内存)
squares = [i ** 2 for i in range(1000000)]

# 生成器表达式(节省内存)
squares = (i ** 2 for i in range(1000000))

# 3. 使用内置函数
# 不好的写法
total = 0
for i in range(100):
    total += i

# 好的写法
total = sum(range(100))

# 4. 避免不必要的循环
# 不好的写法
found = False
for item in items:
    if item == target:
        found = True

# 好的写法
found = target in items

十三、函数

函数就像是一个工具箱,把常用的代码打包起来,需要的时候直接调用。这样可以避免重复写代码,让程序更清晰、更容易维护。

函数的定义和调用

# 最简单的函数
def greet():
    print("你好!")

# 调用函数
greet()  # 输出:你好!

# 带参数的函数
def greet_person(name):
    print(f"你好,{name}!")

greet_person("张三")  # 输出:你好,张三!
greet_person("李四")  # 输出:你好,李四!

# 多个参数
def add(a, b):
    result = a + b
    print(f"{a} + {b} = {result}")

add(3, 5)  # 输出:3 + 5 = 8
add(10, 20)  # 输出:10 + 20 = 30

# 带返回值的函数
def multiply(a, b):
    return a * b

result = multiply(4, 5)
print(result)  # 20

# 可以直接在表达式中使用
print(f"4乘以5等于{multiply(4, 5)}")

# 实际应用:计算圆的面积
def circle_area(radius):
    pi = 3.14159
    area = pi * radius ** 2
    return area

area1 = circle_area(5)
area2 = circle_area(10)
print(f"半径5的圆面积: {area1:.2f}")
print(f"半径10的圆面积: {area2:.2f}")

参数的类型

# 1. 位置参数:按顺序传递
def introduce(name, age, city):
    print(f"我叫{name}{age}岁,来自{city}")

introduce("张三", 25, "北京")  # 必须按顺序

# 2. 关键字参数:指定参数名
introduce(name="李四", age=30, city="上海")
introduce(age=28, city="广州", name="王五")  # 顺序可以变

# 3. 默认参数:有默认值的参数
def greet(name, greeting="你好"):
    print(f"{greeting}{name}!")

greet("张三")  # 使用默认值:你好,张三!
greet("李四", "早上好")  # 自定义:早上好,李四!

# 默认参数必须放在后面
def make_coffee(size, sugar=1, milk=True):
    print(f"制作{size}杯咖啡,糖{sugar}勺,{'加' if milk else '不加'}奶")

make_coffee("大")  # 大杯咖啡,糖1勺,加奶
make_coffee("中", 2)  # 中杯咖啡,糖2勺,加奶
make_coffee("小", 0, False)  # 小杯咖啡,糖0勺,不加奶

# 4. 可变参数:*args(接收任意数量的位置参数)
def sum_all(*numbers):
    total = 0
    for num in numbers:
        total += num
    return total

print(sum_all(1, 2, 3))  # 6
print(sum_all(1, 2, 3, 4, 5))  # 15
print(sum_all(10, 20))  # 30

# 5. 关键字可变参数:**kwargs(接收任意数量的关键字参数)
def print_info(**info):
    for key, value in info.items():
        print(f"{key}: {value}")

print_info(name="张三", age=25, city="北京")
# 输出:
# name: 张三
# age: 25
# city: 北京

# 6. 混合使用(顺序:位置参数、*args、默认参数、**kwargs)
def complex_func(a, b, *args, c=10, **kwargs):
    print(f"a={a}, b={b}")
    print(f"args={args}")
    print(f"c={c}")
    print(f"kwargs={kwargs}")

complex_func(1, 2, 3, 4, 5, c=20, x=100, y=200)
# 输出:
# a=1, b=2
# args=(3, 4, 5)
# c=20
# kwargs={'x': 100, 'y': 200}

返回值

# 返回单个值
def square(x):
    return x ** 2

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

# 返回多个值(实际返回的是元组)
def get_user_info():
    name = "张三"
    age = 25
    city = "北京"
    return name, age, city

# 接收多个返回值
name, age, city = get_user_info()
print(f"{name}, {age}岁, {city}")

# 也可以作为元组接收
info = get_user_info()
print(info)  # ('张三', 25, '北京')

# 没有return语句,默认返回None
def no_return():
    print("这个函数没有返回值")

result = no_return()
print(result)  # None

# 提前返回
def check_age(age):
    if age < 0:
        return "年龄不能为负数"
    if age < 18:
        return "未成年"
    if age < 60:
        return "成年"
    return "老年"

print(check_age(15))  # 未成年
print(check_age(30))  # 成年
print(check_age(-5))  # 年龄不能为负数

# 实际应用:计算成绩等级
def get_grade(score):
    if score < 0 or score > 100:
        return "无效分数"
    if score >= 90:
        return "A"
    if score >= 80:
        return "B"
    if score >= 70:
        return "C"
    if score >= 60:
        return "D"
    return "F"

print(get_grade(95))  # A
print(get_grade(75))  # C
print(get_grade(55))  # F

变量作用域

# 全局变量:在函数外定义
global_var = "我是全局变量"

def test_scope():
    # 局部变量:在函数内定义
    local_var = "我是局部变量"
    print(global_var)  # 可以访问全局变量
    print(local_var)

test_scope()
# print(local_var)  # 错误!函数外无法访问局部变量

# 修改全局变量需要使用global关键字
count = 0

def increment():
    global count  # 声明要修改全局变量
    count += 1
    print(f"count = {count}")

increment()  # count = 1
increment()  # count = 2
print(count)  # 2

# 不使用global会创建新的局部变量
score = 100

def change_score():
    score = 200  # 这是新的局部变量,不影响全局的score
    print(f"函数内: {score}")

change_score()  # 函数内: 200
print(f"函数外: {score}")  # 函数外: 100

# 嵌套函数的作用域
def outer():
    x = "outer"
    
    def inner():
        nonlocal x  # 修改外层函数的变量
        x = "inner"
        print(f"inner函数: {x}")
    
    print(f"调用inner前: {x}")
    inner()
    print(f"调用inner后: {x}")

outer()
# 输出:
# 调用inner前: outer
# inner函数: inner
# 调用inner后: inner

Lambda函数(匿名函数)

# 普通函数
def square(x):
    return x ** 2

# Lambda函数(一行搞定)
square_lambda = lambda x: x ** 2

print(square(5))  # 25
print(square_lambda(5))  # 25

# Lambda函数常用于简单操作
add = lambda a, b: a + b
print(add(3, 5))  # 8

# 实际应用:排序
students = [
    {"name": "张三", "score": 85},
    {"name": "李四", "score": 92},
    {"name": "王五", "score": 78}
]

# 按分数排序
students.sort(key=lambda s: s["score"])
print(students)
# [{'name': '王五', 'score': 78}, {'name': '张三', 'score': 85}, {'name': '李四', 'score': 92}]

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

# 实际应用:过滤列表
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens)  # [2, 4, 6, 8, 10]

# 实际应用:映射列表
squares = list(map(lambda x: x ** 2, numbers))
print(squares)  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# Lambda函数的限制:只能写一个表达式,不能包含复杂逻辑
# 复杂逻辑还是用普通函数

递归函数

# 递归:函数调用自己
# 经典例子:计算阶乘
def factorial(n):
    if n == 0 or n == 1:
        return 1  # 基准情况
    else:
        return n * factorial(n - 1)  # 递归调用

print(factorial(5))  # 5! = 5×4×3×2×1 = 120
print(factorial(10))  # 3628800

# 经典例子:斐波那契数列
def fibonacci(n):
    if n <= 1:
        return n
    else:
        return fibonacci(n - 1) + fibonacci(n - 2)

# 打印前10个斐波那契数
for i in range(10):
    print(fibonacci(i), end=" ")
print()  # 0 1 1 2 3 5 8 13 21 34

# 实际应用:计算幂
def power(base, exp):
    if exp == 0:
        return 1
    else:
        return base * power(base, exp - 1)

print(power(2, 5))  # 2^5 = 32

# 实际应用:遍历嵌套列表
def flatten(nested_list):
    result = []
    for item in nested_list:
        if isinstance(item, list):
            result.extend(flatten(item))  # 递归处理子列表
        else:
            result.append(item)
    return result

nested = [1, [2, 3], [4, [5, 6]], 7]
flat = flatten(nested)
print(flat)  # [1, 2, 3, 4, 5, 6, 7]

# 注意:递归深度有限制,太深会报错
# import sys
# print(sys.getrecursionlimit())  # 默认1000

文档字符串(Docstring)

# 函数的说明文档,用三引号
def calculate_bmi(weight, height):
    """
    计算BMI指数
    
    参数:
        weight (float): 体重,单位kg
        height (float): 身高,单位m
    
    返回:
        float: BMI指数
    
    示例:
        >>> calculate_bmi(70, 1.75)
        22.86
    """
    bmi = weight / (height ** 2)
    return round(bmi, 2)

# 查看文档
print(calculate_bmi.__doc__)

# 使用help()查看
help(calculate_bmi)

# 实际应用:完整的函数文档
def process_data(data, method="average", ignore_negative=True):
    """
    处理数据列表
    
    这个函数可以对数据列表进行各种统计处理。
    
    参数:
        data (list): 数字列表
        method (str): 处理方法,可选 'average', 'sum', 'max', 'min'
        ignore_negative (bool): 是否忽略负数
    
    返回:
        float: 处理结果
    
    异常:
        ValueError: 如果data为空或method无效
    
    示例:
        >>> process_data([1, 2, 3, 4, 5])
        3.0
        >>> process_data([1, -2, 3, -4, 5], ignore_negative=False)
        0.6
    """
    if not data:
        raise ValueError("数据列表不能为空")
    
    if ignore_negative:
        data = [x for x in data if x >= 0]
    
    if method == "average":
        return sum(data) / len(data)
    elif method == "sum":
        return sum(data)
    elif method == "max":
        return max(data)
    elif method == "min":
        return min(data)
    else:
        raise ValueError(f"无效的方法: {method}")

函数的高级特性

# 1. 函数作为参数传递
def apply_operation(x, y, operation):
    return operation(x, y)

def add(a, b):
    return a + b

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

print(apply_operation(5, 3, add))  # 8
print(apply_operation(5, 3, multiply))  # 15

# 2. 函数作为返回值
def make_multiplier(n):
    def multiplier(x):
        return x * n
    return multiplier

times_3 = make_multiplier(3)
times_5 = make_multiplier(5)

print(times_3(10))  # 30
print(times_5(10))  # 50

# 3. 闭包
def counter():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

c1 = counter()
print(c1())  # 1
print(c1())  # 2
print(c1())  # 3

c2 = counter()
print(c2())  # 1(新的计数器)

# 4. 装饰器(高级话题,简单了解)
def timer_decorator(func):
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__}执行时间: {end - start:.4f}秒")
        return result
    return wrapper

@timer_decorator
def slow_function():
    import time
    time.sleep(1)
    print("函数执行完毕")

slow_function()
# 输出:
# 函数执行完毕
# slow_function执行时间: 1.0001秒

十四、数据结构详解

Python内置了几种强大的数据结构,每种都有丰富的方法和接口。掌握这些数据结构是写好Python代码的基础。

列表(List)的方法

# 创建列表
fruits = ["苹果", "香蕉", "橙子"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True]
empty = []

# ========== 添加元素 ==========

# append():在末尾添加一个元素
fruits.append("葡萄")
print(fruits)  # ['苹果', '香蕉', '橙子', '葡萄']

# insert():在指定位置插入元素
fruits.insert(1, "西瓜")  # 在索引1的位置插入
print(fruits)  # ['苹果', '西瓜', '香蕉', '橙子', '葡萄']

# extend():添加多个元素(合并列表)
fruits.extend(["芒果", "草莓"])
print(fruits)  # ['苹果', '西瓜', '香蕉', '橙子', '葡萄', '芒果', '草莓']

# 注意append和extend的区别
list1 = [1, 2, 3]
list1.append([4, 5])
print(list1)  # [1, 2, 3, [4, 5]](整个列表作为一个元素)

list2 = [1, 2, 3]
list2.extend([4, 5])
print(list2)  # [1, 2, 3, 4, 5](逐个添加元素)

# ========== 删除元素 ==========

# remove():删除第一个匹配的元素
fruits = ["苹果", "香蕉", "橙子", "香蕉"]
fruits.remove("香蕉")
print(fruits)  # ['苹果', '橙子', '香蕉'](只删除第一个)

# pop():删除并返回指定位置的元素(默认最后一个)
fruits = ["苹果", "香蕉", "橙子"]
last = fruits.pop()
print(last)  # 橙子
print(fruits)  # ['苹果', '香蕉']

first = fruits.pop(0)
print(first)  # 苹果
print(fruits)  # ['香蕉']

# del:删除指定位置或切片
fruits = ["苹果", "香蕉", "橙子", "葡萄", "西瓜"]
del fruits[1]
print(fruits)  # ['苹果', '橙子', '葡萄', '西瓜']

del fruits[1:3]
print(fruits)  # ['苹果', '西瓜']

# clear():清空列表
fruits.clear()
print(fruits)  # []

# ========== 查找和统计 ==========

numbers = [1, 2, 3, 2, 4, 2, 5]

# index():查找元素的索引
idx = numbers.index(3)
print(idx)  # 2

# 查找指定范围内的索引
idx = numbers.index(2, 2)  # 从索引2开始查找
print(idx)  # 3

# count():统计元素出现次数
count = numbers.count(2)
print(count)  # 3

# in:检查元素是否存在
print(3 in numbers)  # True
print(10 in numbers)  # False

# ========== 排序和反转 ==========

numbers = [3, 1, 4, 1, 5, 9, 2, 6]

# sort():原地排序(修改原列表)
numbers.sort()
print(numbers)  # [1, 1, 2, 3, 4, 5, 6, 9]

# 降序排序
numbers.sort(reverse=True)
print(numbers)  # [9, 6, 5, 4, 3, 2, 1, 1]

# sorted():返回新列表(不修改原列表)
numbers = [3, 1, 4, 1, 5]
sorted_numbers = sorted(numbers)
print(numbers)  # [3, 1, 4, 1, 5](原列表不变)
print(sorted_numbers)  # [1, 1, 3, 4, 5]

# 自定义排序
students = [
    {"name": "张三", "score": 85},
    {"name": "李四", "score": 92},
    {"name": "王五", "score": 78}
]
students.sort(key=lambda s: s["score"], reverse=True)
print(students)  # 按分数降序

# reverse():反转列表
numbers = [1, 2, 3, 4, 5]
numbers.reverse()
print(numbers)  # [5, 4, 3, 2, 1]

# ========== 复制列表 ==========

# 浅拷贝
original = [1, 2, 3]
copy1 = original.copy()
copy2 = original[:]
copy3 = list(original)

copy1.append(4)
print(original)  # [1, 2, 3](不受影响)
print(copy1)  # [1, 2, 3, 4]

# 注意:浅拷贝对嵌套列表的影响
original = [[1, 2], [3, 4]]
copy = original.copy()
copy[0].append(3)
print(original)  # [[1, 2, 3], [3, 4]](内层列表被修改)
print(copy)  # [[1, 2, 3], [3, 4]]

# 深拷贝
import copy
original = [[1, 2], [3, 4]]
deep_copy = copy.deepcopy(original)
deep_copy[0].append(3)
print(original)  # [[1, 2], [3, 4]](不受影响)
print(deep_copy)  # [[1, 2, 3], [3, 4]]

# ========== 其他常用操作 ==========

# len():获取长度
fruits = ["苹果", "香蕉", "橙子"]
print(len(fruits))  # 3

# min()和max():最小值和最大值
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print(min(numbers))  # 1
print(max(numbers))  # 9

# sum():求和
print(sum(numbers))  # 31

# 列表拼接
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = list1 + list2
print(combined)  # [1, 2, 3, 4, 5, 6]

# 列表重复
repeated = [1, 2] * 3
print(repeated)  # [1, 2, 1, 2, 1, 2]

# 列表切片赋值
numbers = [1, 2, 3, 4, 5]
numbers[1:4] = [20, 30]
print(numbers)  # [1, 20, 30, 5]

元组(Tuple)的方法

# 创建元组
point = (3, 5)
person = ("张三", 25, "北京")
single = (5,)  # 单元素元组要加逗号
empty = ()

# 元组是不可变的,但方法较少
numbers = (1, 2, 3, 2, 4, 2, 5)

# count():统计元素出现次数
print(numbers.count(2))  # 3

# index():查找元素索引
print(numbers.index(3))  # 2

# 元组的其他操作
# len():长度
print(len(numbers))  # 7

# in:检查元素
print(3 in numbers)  # True

# 拼接
tuple1 = (1, 2, 3)
tuple2 = (4, 5, 6)
combined = tuple1 + tuple2
print(combined)  # (1, 2, 3, 4, 5, 6)

# 重复
repeated = (1, 2) * 3
print(repeated)  # (1, 2, 1, 2, 1, 2)

# 元组解包
point = (3, 5)
x, y = point
print(f"x={x}, y={y}")  # x=3, y=5

# 交换变量
a, b = 10, 20
a, b = b, a
print(a, b)  # 20 10

# 函数返回多个值(实际是元组)
def get_min_max(numbers):
    return min(numbers), max(numbers)

minimum, maximum = get_min_max([1, 5, 3, 9, 2])
print(f"最小值: {minimum}, 最大值: {maximum}")

# 元组虽然不可变,但如果包含可变对象,可变对象可以修改
tuple_with_list = (1, 2, [3, 4])
tuple_with_list[2].append(5)
print(tuple_with_list)  # (1, 2, [3, 4, 5])

# 命名元组(更清晰的元组)
from collections import namedtuple

Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 5)
print(p.x, p.y)  # 3 5
print(p[0], p[1])  # 3 5(也可以用索引)

Person = namedtuple('Person', ['name', 'age', 'city'])
person = Person('张三', 25, '北京')
print(person.name)  # 张三
print(person.age)  # 25

字典(Dictionary)的方法

# 创建字典
student = {
    "name": "张三",
    "age": 18,
    "grade": "高三"
}

# 空字典
empty = {}
empty2 = dict()

# ========== 访问和修改 ==========

# 访问值
print(student["name"])  # 张三

# get():安全访问(不存在返回None或默认值)
print(student.get("name"))  # 张三
print(student.get("score"))  # None
print(student.get("score", 0))  # 0(默认值)

# 修改值
student["age"] = 19
print(student)

# 添加新键值对
student["score"] = 85
print(student)

# ========== 删除操作 ==========

# del:删除键值对
del student["grade"]
print(student)

# pop():删除并返回值
score = student.pop("score")
print(score)  # 85
print(student)

# pop()带默认值
result = student.pop("nonexistent", "不存在")
print(result)  # 不存在

# popitem():删除并返回最后一个键值对(Python 3.7+保证顺序)
student = {"name": "张三", "age": 18, "city": "北京"}
item = student.popitem()
print(item)  # ('city', '北京')
print(student)

# clear():清空字典
student.clear()
print(student)  # {}

# ========== 查询操作 ==========

student = {"name": "张三", "age": 18, "city": "北京"}

# keys():获取所有键
keys = student.keys()
print(keys)  # dict_keys(['name', 'age', 'city'])
print(list(keys))  # ['name', 'age', 'city']

# values():获取所有值
values = student.values()
print(list(values))  # ['张三', 18, '北京']

# items():获取所有键值对
items = student.items()
print(list(items))  # [('name', '张三'), ('age', 18), ('city', '北京')]

# 遍历字典
for key in student:
    print(f"{key}: {student[key]}")

for key, value in student.items():
    print(f"{key}: {value}")

# in:检查键是否存在
print("name" in student)  # True
print("score" in student)  # False

# ========== 更新操作 ==========

# update():更新字典
student = {"name": "张三", "age": 18}
student.update({"age": 19, "city": "北京"})
print(student)  # {'name': '张三', 'age': 19, 'city': '北京'}

# 也可以用关键字参数
student.update(score=85, grade="高三")
print(student)

# setdefault():如果键不存在则设置默认值
student.setdefault("hobby", "篮球")
print(student)  # 添加了hobby

student.setdefault("name", "李四")  # name已存在,不修改
print(student["name"])  # 还是张三

# ========== 字典推导式 ==========

# 创建字典
squares = {x: x**2 for x in range(5)}
print(squares)  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

# 过滤字典
student_scores = {"张三": 85, "李四": 92, "王五": 78, "赵六": 88}
high_scores = {name: score for name, score in student_scores.items() if score >= 85}
print(high_scores)  # {'张三': 85, '李四': 92, '赵六': 88}

# 交换键值
original = {"a": 1, "b": 2, "c": 3}
swapped = {value: key for key, value in original.items()}
print(swapped)  # {1: 'a', 2: 'b', 3: 'c'}

# ========== 嵌套字典 ==========

students = {
    "001": {"name": "张三", "age": 18, "score": 85},
    "002": {"name": "李四", "age": 19, "score": 92},
    "003": {"name": "王五", "age": 18, "score": 78}
}

# 访问嵌套值
print(students["001"]["name"])  # 张三

# 遍历嵌套字典
for student_id, info in students.items():
    print(f"学号: {student_id}")
    for key, value in info.items():
        print(f"  {key}: {value}")

# ========== 字典的其他技巧 ==========

# 合并字典(Python 3.9+)
dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3, "d": 4}
merged = dict1 | dict2
print(merged)  # {'a': 1, 'b': 2, 'c': 3, 'd': 4}

# 旧版本的合并方法
merged = {**dict1, **dict2}
print(merged)

# 从两个列表创建字典
keys = ["name", "age", "city"]
values = ["张三", 25, "北京"]
person = dict(zip(keys, values))
print(person)  # {'name': '张三', 'age': 25, 'city': '北京'}

# defaultdict:带默认值的字典
from collections import defaultdict

# 统计单词出现次数
word_count = defaultdict(int)  # 默认值为0
words = ["apple", "banana", "apple", "orange", "banana", "apple"]
for word in words:
    word_count[word] += 1
print(dict(word_count))  # {'apple': 3, 'banana': 2, 'orange': 1}

# Counter:专门用于计数
from collections import Counter

words = ["apple", "banana", "apple", "orange", "banana", "apple"]
counter = Counter(words)
print(counter)  # Counter({'apple': 3, 'banana': 2, 'orange': 1})
print(counter.most_common(2))  # [('apple', 3), ('banana', 2)]

集合(Set)的方法

# 创建集合
fruits = {"苹果", "香蕉", "橙子"}
numbers = {1, 2, 3, 4, 5}
empty = set()  # 注意:{}是空字典,不是空集合

# 集合自动去重
numbers = {1, 2, 2, 3, 3, 3, 4}
print(numbers)  # {1, 2, 3, 4}

# ========== 添加和删除 ==========

# add():添加单个元素
fruits = {"苹果", "香蕉"}
fruits.add("橙子")
print(fruits)  # {'苹果', '香蕉', '橙子'}

# update():添加多个元素
fruits.update(["葡萄", "西瓜"])
print(fruits)

# remove():删除元素(不存在会报错)
fruits.remove("香蕉")
print(fruits)

# discard():删除元素(不存在不报错)
fruits.discard("芒果")  # 不存在,但不报错
print(fruits)

# pop():随机删除并返回一个元素
item = fruits.pop()
print(f"删除了: {item}")
print(fruits)

# clear():清空集合
fruits.clear()
print(fruits)  # set()

# ========== 集合运算 ==========

set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}

# 并集(所有元素)
union = set1 | set2
print(union)  # {1, 2, 3, 4, 5, 6, 7, 8}
print(set1.union(set2))  # 同上

# 交集(共同元素)
intersection = set1 & set2
print(intersection)  # {4, 5}
print(set1.intersection(set2))  # 同上

# 差集(在set1但不在set2)
difference = set1 - set2
print(difference)  # {1, 2, 3}
print(set1.difference(set2))  # 同上

# 对称差集(不同时在两个集合中的元素)
sym_diff = set1 ^ set2
print(sym_diff)  # {1, 2, 3, 6, 7, 8}
print(set1.symmetric_difference(set2))  # 同上

# ========== 集合关系 ==========

set_a = {1, 2, 3}
set_b = {1, 2, 3, 4, 5}
set_c = {6, 7, 8}

# 子集
print(set_a.issubset(set_b))  # True(set_a是set_b的子集)
print(set_a <= set_b)  # True

# 超集
print(set_b.issuperset(set_a))  # True(set_b是set_a的超集)
print(set_b >= set_a)  # True

# 不相交(没有共同元素)
print(set_a.isdisjoint(set_c))  # True(没有共同元素)
print(set_a.isdisjoint(set_b))  # False(有共同元素)

# ========== 集合推导式 ==========

# 创建集合
squares = {x**2 for x in range(10)}
print(squares)  # {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}

# 过滤集合
numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
evens = {x for x in numbers if x % 2 == 0}
print(evens)  # {2, 4, 6, 8, 10}

# ========== 集合的实际应用 ==========

# 1. 去重
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique = list(set(numbers))
print(unique)  # [1, 2, 3, 4]

# 2. 查找共同好友
user1_friends = {"张三", "李四", "王五", "赵六"}
user2_friends = {"李四", "王五", "孙七", "周八"}
common_friends = user1_friends & user2_friends
print(f"共同好友: {common_friends}")  # {'李四', '王五'}

# 3. 查找独有好友
only_user1 = user1_friends - user2_friends
print(f"只有用户1有的好友: {only_user1}")  # {'张三', '赵六'}

# 4. 检查权限
user_permissions = {"read", "write", "delete"}
required_permissions = {"read", "write"}
has_permission = required_permissions.issubset(user_permissions)
print(f"有权限: {has_permission}")  # True

# 5. 统计不同的字符
text = "hello world"
unique_chars = set(text)
print(f"不同的字符: {unique_chars}")
print(f"字符种类数: {len(unique_chars)}")

# 6. 快速成员检查(集合比列表快得多)
# 列表检查:O(n)
large_list = list(range(1000000))
print(999999 in large_list)  # 慢

# 集合检查:O(1)
large_set = set(range(1000000))
print(999999 in large_set)  # 快

# ========== frozenset(不可变集合)==========

# frozenset是不可变的集合,可以作为字典的键
immutable_set = frozenset([1, 2, 3, 4, 5])
print(immutable_set)  # frozenset({1, 2, 3, 4, 5})

# 不能修改
# immutable_set.add(6)  # 报错!AttributeError

# 可以作为字典的键
set_dict = {
    frozenset([1, 2]): "集合1",
    frozenset([3, 4]): "集合2"
}
print(set_dict[frozenset([1, 2])])  # 集合1

# frozenset支持集合运算
fs1 = frozenset([1, 2, 3])
fs2 = frozenset([3, 4, 5])
print(fs1 | fs2)  # frozenset({1, 2, 3, 4, 5})
print(fs1 & fs2)  # frozenset({3})

字符串(String)的高级方法

# ========== 大小写转换 ==========

text = "Hello World"

# upper():全部大写
print(text.upper())  # HELLO WORLD

# lower():全部小写
print(text.lower())  # hello world

# capitalize():首字母大写,其余小写
print(text.capitalize())  # Hello world

# title():每个单词首字母大写
print(text.title())  # Hello World

# swapcase():大小写互换
print(text.swapcase())  # hELLO wORLD

# casefold():更激进的小写(处理特殊字符)
german = "ß"
print(german.lower())  # ß
print(german.casefold())  # ss

# ========== 查找和替换 ==========

text = "Python is awesome. Python is powerful."

# find():查找子串位置(找不到返回-1)
pos = text.find("Python")
print(pos)  # 0

pos = text.find("Python", 10)  # 从位置10开始查找
print(pos)  # 19

pos = text.find("Java")
print(pos)  # -1(找不到)

# rfind():从右边开始查找
pos = text.rfind("Python")
print(pos)  # 19

# index():查找子串位置(找不到会报错)
pos = text.index("Python")
print(pos)  # 0
# pos = text.index("Java")  # 报错!ValueError

# count():统计子串出现次数
count = text.count("Python")
print(count)  # 2

# replace():替换子串
new_text = text.replace("Python", "Java")
print(new_text)  # Java is awesome. Java is powerful.

# 限制替换次数
new_text = text.replace("Python", "Java", 1)
print(new_text)  # Java is awesome. Python is powerful.

# ========== 分割和连接 ==========

# split():分割字符串(返回列表)
text = "apple,banana,orange"
fruits = text.split(",")
print(fruits)  # ['apple', 'banana', 'orange']

# 默认按空格分割
text = "Hello World Python"
words = text.split()
print(words)  # ['Hello', 'World', 'Python']

# 限制分割次数
text = "a-b-c-d-e"
parts = text.split("-", 2)
print(parts)  # ['a', 'b', 'c-d-e']

# rsplit():从右边开始分割
parts = text.rsplit("-", 2)
print(parts)  # ['a-b-c', 'd', 'e']

# splitlines():按行分割
text = "第一行\n第二行\n第三行"
lines = text.splitlines()
print(lines)  # ['第一行', '第二行', '第三行']

# join():连接字符串
words = ["Hello", "World", "Python"]
sentence = " ".join(words)
print(sentence)  # Hello World Python

# 用不同的分隔符
csv = ",".join(words)
print(csv)  # Hello,World,Python

# ========== 去除空白 ==========

text = "   Hello World   "

# strip():去除两端空白
print(text.strip())  # "Hello World"

# lstrip():去除左边空白
print(text.lstrip())  # "Hello World   "

# rstrip():去除右边空白
print(text.rstrip())  # "   Hello World"

# 去除指定字符
text = "***Hello***"
print(text.strip("*"))  # "Hello"

# ========== 判断方法 ==========

# startswith():是否以指定字符串开头
text = "Python is great"
print(text.startswith("Python"))  # True
print(text.startswith("Java"))  # False

# 可以指定范围
print(text.startswith("is", 7))  # True

# endswith():是否以指定字符串结尾
filename = "document.pdf"
print(filename.endswith(".pdf"))  # True
print(filename.endswith(".txt"))  # False

# isdigit():是否全是数字
print("123".isdigit())  # True
print("12.3".isdigit())  # False
print("12a".isdigit())  # False

# isalpha():是否全是字母
print("abc".isalpha())  # True
print("abc123".isalpha())  # False

# isalnum():是否全是字母或数字
print("abc123".isalnum())  # True
print("abc 123".isalnum())  # False

# isspace():是否全是空白字符
print("   ".isspace())  # True
print(" a ".isspace())  # False

# islower():是否全是小写
print("hello".islower())  # True
print("Hello".islower())  # False

# isupper():是否全是大写
print("HELLO".isupper())  # True
print("Hello".isupper())  # False

# istitle():是否是标题格式(每个单词首字母大写)
print("Hello World".istitle())  # True
print("Hello world".istitle())  # False

# ========== 对齐和填充 ==========

text = "Python"

# center():居中对齐
print(text.center(20))  # "       Python       "
print(text.center(20, "*"))  # "*******Python*******"

# ljust():左对齐
print(text.ljust(20))  # "Python              "
print(text.ljust(20, "-"))  # "Python--------------"

# rjust():右对齐
print(text.rjust(20))  # "              Python"
print(text.rjust(20, "-"))  # "--------------Python"

# zfill():用0填充(常用于数字)
number = "42"
print(number.zfill(5))  # "00042"

# ========== 编码和解码 ==========

# encode():字符串转字节
text = "你好,世界"
bytes_data = text.encode("utf-8")
print(bytes_data)  # b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c'

# decode():字节转字符串
decoded = bytes_data.decode("utf-8")
print(decoded)  # 你好,世界

# ========== 格式化方法 ==========

# format():格式化字符串
name = "张三"
age = 25
text = "我叫{},今年{}岁".format(name, age)
print(text)  # 我叫张三,今年25岁

# 指定位置
text = "我叫{0},今年{1}岁,{0}很高兴认识你".format(name, age)
print(text)

# 指定名称
text = "我叫{name},今年{age}岁".format(name=name, age=age)
print(text)

# format_map():用字典格式化
person = {"name": "李四", "age": 30}
text = "我叫{name},今年{age}岁".format_map(person)
print(text)

# ========== 其他实用方法 ==========

# partition():分割成三部分
text = "Python is awesome"
parts = text.partition("is")
print(parts)  # ('Python ', 'is', ' awesome')

# rpartition():从右边分割
parts = text.rpartition("is")
print(parts)  # ('Python ', 'is', ' awesome')

# expandtabs():展开制表符
text = "Name\tAge\tCity"
print(text.expandtabs(10))  # Name      Age       City

# translate():字符映射转换
# 创建转换表
trans_table = str.maketrans("aeiou", "12345")
text = "hello world"
print(text.translate(trans_table))  # h2ll4 w4rld

# 删除字符
trans_table = str.maketrans("", "", "aeiou")
print(text.translate(trans_table))  # hll wrld

十五、文件操作

1. 打开与关闭文件

在 Python 中,操作文件的基本流程是:打开文件 -> 操作文件 (读/写) -> 关闭文件

1.1 open() 函数

open() 是 Python 的内置函数,用于打开一个文件并返回一个文件对象(File Object)。

基本语法:

file_object = open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
  • file: 文件路径(相对路径或绝对路径)。
  • mode: 文件打开模式(详见下一节)。
  • encoding: 编码格式,处理文本文件时强烈建议指定(如 encoding='utf-8'),避免乱码。
1.2 close() 函数

文件操作完成后,必须调用 close() 方法释放系统资源。如果不关闭文件,可能会导致内存泄漏或数据未成功写入磁盘。

传统写法(不推荐):

f = open('example.txt', 'w', encoding='utf-8')
f.write('Hello, World!')
f.close() # 容易被遗忘,或在报错时无法执行到
1.3 使用 with 上下文管理器

为了防止忘记调用 close() 或者在读写过程中发生异常导致文件未关闭,Python 提供了 with 语句。它可以自动帮你管理文件的关闭,即使代码块中抛出了异常。

with open('example.txt', 'w', encoding='utf-8') as f:
    f.write('Hello, Python!')
# 离开 with 代码块后,文件 f 已经被自动关闭

2. 文件打开模式 (Mode)

open() 函数的 mode 参数决定了你将以何种方式操作文件。以下是模式对照表:

模式 描述 特点说明
'r' 只读 (默认) 从头开始读。如果文件不存在,抛出 FileNotFoundError 异常。
'w' 只写 覆盖已有文件。如果文件不存在,则创建新文件。
'x' 独占创建 创建新文件并写入。如果文件已存在,则抛出 FileExistsError 异常。
'a' 追加 在文件末尾追加内容。如果文件不存在,则创建新文件。
'b' 二进制模式 与其他模式结合使用(如 'rb', 'wb'),用于处理非文本文件(图片、音频等)。
't' 文本模式 (默认) 与其他模式结合使用(如 'rt',通常省略 't')。
'+' 读写模式 与其他模式结合使用(如 'r+', 'w+', 'a+'),使文件既可读也可写。

3. 读取文件 (Read)

Python 提供了多种读取文件内容的方法,适用于不同的场景。

3.1 read(size):读取指定字符或全部内容
  • 说明:如果不指定 size,则一次性读取整个文件内容。
  • 适用场景:文件较小,内存足够时。
with open('example.txt', 'r', encoding='utf-8') as f:
    content = f.read()
    print("全部内容:\n", content)
3.2 readline():逐行读取
  • 说明:每次调用只读取文件中的一行(保留行尾的换行符 \n)。
  • 适用场景:处理超大文件,内存有限时。
with open('example.txt', 'r', encoding='utf-8') as f:
    line = f.readline()
    while line:
        print("单行内容:", line.strip()) # strip() 去除首尾空白符和换行符
        line = f.readline()
3.3 readlines():读取所有行并返回列表
  • 说明:将文件按行读取,每行作为列表中的一个元素。
with open('example.txt', 'r', encoding='utf-8') as f:
    lines = f.readlines()
    for line in lines:
        print(line.strip())
3.4 遍历文件对象

文件对象本身就是一个可迭代对象(Iterable),这是处理大文件最推荐的方式。

with open('example.txt', 'r', encoding='utf-8') as f:
    for line in f:
        print(line.strip())

4. 写入文件 (Write)

写入文件同样有不同的方法,需要注意 'w' 模式会覆盖原文件,而 'a' 模式是在末尾追加。

4.1 write(string):写入字符串
  • 说明:将字符串写入文件。注意,它不会自动帮你添加换行符,需要手动加 \n
with open('output.txt', 'w', encoding='utf-8') as f:
    f.write("这是第一行。\n")
    f.write("这是第二行。\n")
4.2 writelines(iterable):写入可迭代对象
  • 说明:接受一个字符串列表(或其它可迭代对象)并写入文件。同样,它不会自动添加换行符。
lines_to_write = ["苹果\n", "香蕉\n", "橙子\n"]
with open('fruits.txt', 'w', encoding='utf-8') as f:
    f.writelines(lines_to_write)

5. 文件指针

文件操作有一个“指针”(光标)的概念,记录着当前读写到的位置。

5.1 tell():获取当前指针位置
  • 返回:当前文件指针相对于文件开头的字节数。
5.2 seek(offset, whence):移动文件指针
  • offset:偏移的字节数。
  • whence:相对位置。0 表示从文件开头算起(默认);1 表示从当前位置算起;2 表示从文件末尾算起。(注意:在文本模式下,whence 只能为 0;如果要使用 12,通常需要以二进制模式 'rb' 打开)。
with open('example.txt', 'rb') as f: # 二进制模式
    print(f.read(5))      # 读取前5个字节
    print(f.tell())       # 输出当前指针位置: 5
    
    f.seek(0, 0)          # 将指针移回文件开头
    print(f.read(3))      # 重新从头读取3个字节
    
    f.seek(-2, 2)         # 将指针移动到倒数第2个字节处
    print(f.read())       # 读取最后两个字节

好的!虽然我无法直接访问该 CSDN 链接,但根据我对该类高质量文章的了解,我为您的博客大幅扩充了以下内容。这些章节可以直接无缝衔接到您现有的第 5 节之后,让整篇博客从"基础读写"跃升为"全方位文件操作手册"。


6. 文件对象的其他常用属性与方法

除了前面介绍的读写和指针操作外,文件对象本身还有一些非常实用的属性和方法。

6.1 文件对象的常用属性
属性 说明
f.name 返回文件的名称(路径)
f.mode 返回文件打开时使用的模式
f.closed 判断文件是否已经关闭,返回 TrueFalse
f.encoding 返回文件使用的编码格式(仅文本模式)
with open('example.txt', 'r', encoding='utf-8') as f:
    print("文件名:", f.name)        # example.txt
    print("打开模式:", f.mode)      # r
    print("编码格式:", f.encoding)  # utf-8
    print("是否已关闭:", f.closed)  # False

print("离开 with 后是否已关闭:", f.closed)  # True
6.2 flush():强制刷新缓冲区
  • 说明write() 在调用时,数据不一定会立即写入磁盘,可能会暂时存在内存的缓冲区中。调用 flush() 可以强制将缓冲区的数据立即写入文件,而无需等待文件关闭。
  • 适用场景:在实时日志记录长时间运行脚本中非常有用,可以防止程序意外中断时丢失数据。
import time

with open('realtime_log.txt', 'w', encoding='utf-8') as f:
    for i in range(5):
        f.write(f"日志记录 {i}: 当前时间 {time.strftime('%H:%M:%S')}\n")
        f.flush()  # 每写一条就立即刷新到磁盘,防止崩溃时丢失
        print(f"第 {i} 条日志已写入磁盘")
        time.sleep(1) # 模拟耗时操作
6.3 truncate(size):截断文件
  • 说明:将文件截断到指定的 size 字节。如果不指定 size,则从当前文件指针位置截断(即删除指针之后的所有内容)。
  • 注意:需要以可写模式(如 'r+', 'w', 'a')打开文件。
# 先准备一个文件
with open('trunc_test.txt', 'w', encoding='utf-8') as f:
    f.write("Hello, Python World!")  # 20个字符

# 截断文件,只保留前 13 个字节
with open('trunc_test.txt', 'r+', encoding='utf-8') as f:
    f.truncate(13)

with open('trunc_test.txt', 'r', encoding='utf-8') as f:
    print(f.read())  # 输出: Hello, Python

7. 文件编码与乱码问题

编码问题是文件操作中最常见的坑之一,尤其是在跨平台(Windows / Mac / Linux)开发时。

7.1 什么是文件编码?

文件在磁盘上本质是一串二进制字节流。编码(Encoding)就是"字符"与"字节"之间的映射规则。常见编码:

编码 说明
ASCII 最早的编码,仅支持 128 个英文字符,1 字节/字符
GBK / GB2312 中文编码标准,Windows 中文系统默认编码,2 字节/中文
UTF-8 国际通用编码,可变长度(英文 1 字节,中文 3 字节),推荐使用
7.2 乱码产生的原因

核心原因:写入时用的编码 ≠ 读取时用的编码

# 用 GBK 编码写入
with open('gbk_file.txt', 'w', encoding='gbk') as f:
    f.write('你好,世界')

# 用 UTF-8 编码读取 —— 产生乱码或报错!
try:
    with open('gbk_file.txt', 'r', encoding='utf-8') as f:
        print(f.read())
except UnicodeDecodeError as e:
    print(f"解码错误: {e}")
7.3 解决方案:检测文件编码

当你拿到一个不确定编码的文件时,可以使用第三方库 chardet 来自动检测。

pip install chardet
import chardet

# 以二进制模式读取原始字节
with open('gbk_file.txt', 'rb') as f:
    raw_data = f.read()
    result = chardet.detect(raw_data)
    print("检测结果:", result)
    # 输出类似: {'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}

# 用检测到的编码去正确读取
detected_encoding = result['encoding']
with open('gbk_file.txt', 'r', encoding=detected_encoding) as f:
    print("正确内容:", f.read())  # 你好,世界
7.4 编码转换实战:GBK 转 UTF-8
def convert_encoding(src_file, dst_file, src_enc='gbk', dst_enc='utf-8'):
    """将文件从一种编码转换为另一种编码"""
    with open(src_file, 'r', encoding=src_enc) as f_in:
        content = f_in.read()
    with open(dst_file, 'w', encoding=dst_enc) as f_out:
        f_out.write(content)
    print(f"已将 {src_file}{src_enc} 转换为 {dst_enc},保存到 {dst_file}")

convert_encoding('gbk_file.txt', 'utf8_file.txt')

8. 二进制文件操作

图片、音频、视频、可执行文件等都属于二进制文件,不能以文本模式打开,必须使用 'b' 模式。

8.1 复制二进制文件(如图片)
def copy_binary_file(src, dst, chunk_size=1024):
    """
    以二进制方式复制文件(适用于任何文件类型)
    chunk_size: 每次读取的字节数,避免大文件撑爆内存
    """
    with open(src, 'rb') as f_in, open(dst, 'wb') as f_out:
        while True:
            chunk = f_in.read(chunk_size)
            if not chunk:  # 读完了
                break
            f_out.write(chunk)
    print(f"文件复制完成: {src} -> {dst}")

# 示例:复制一张图片
# copy_binary_file('photo.jpg', 'photo_backup.jpg')

知识点:上面的 with open(...) as f_in, open(...) as f_out: 语法可以同时打开两个文件,它们都会在退出 with 块时自动关闭。

8.2 读取文件的二进制头部(判断文件类型)

不同类型的文件有不同的"魔数"(Magic Number),即文件开头的几个字节。通过读取这些字节,我们可以判断文件的真实类型,而不是依赖文件后缀名。

def detect_file_type(filepath):
    """通过文件头部的魔数判断文件类型"""
    magic_numbers = {
        b'\x89PNG': 'PNG 图片',
        b'\xff\xd8\xff': 'JPEG 图片',
        b'GIF8': 'GIF 图片',
        b'PK': 'ZIP 压缩文件 (或 .docx/.xlsx)',
        b'%PDF': 'PDF 文档',
    }
    with open(filepath, 'rb') as f:
        header = f.read(8)  # 读取前8个字节即可
    
    for magic, file_type in magic_numbers.items():
        if header.startswith(magic):
            return file_type
    return '未知类型'

# print(detect_file_type('test.png'))  # PNG 图片

十六、数据可视化

Python的数据可视化生态非常强大,最常用的库是matplotlibseaborn。通过几行代码就能把枯燥的数据变成直观的图表。

安装必要的库

# 在终端中执行
# pip install matplotlib seaborn pandas numpy

matplotlib基础

matplotlib是Python最基础的绑图库,几乎所有其他可视化库都是基于它构建的。

import matplotlib.pyplot as plt

# 最简单的折线图
x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]

plt.plot(x, y)
plt.title("My First Plot")
plt.xlabel("X Axis")
plt.ylabel("Y Axis")
plt.show()

中文显示设置

matplotlib默认不支持中文,需要手动设置字体:

import matplotlib.pyplot as plt

# Windows系统
plt.rcParams['font.sans-serif'] = ['SimHei']
# macOS系统
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
# Linux系统
# plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei']

# 解决负号显示问题
plt.rcParams['axes.unicode_minus'] = False

# 现在可以正常显示中文了
plt.plot([1, 2, 3], [4, 5, 6])
plt.title("我的第一张图")
plt.xlabel("横轴")
plt.ylabel("纵轴")
plt.show()

折线图

import matplotlib.pyplot as plt

# 模拟一周的气温数据
days = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
temperature = [23, 25, 22, 26, 28, 30, 27]

plt.figure(figsize=(10, 6),dpi=80)  # 设置图表大小
# 在图片模糊的时候调整dpi来变清晰
plt.plot(days, temperature, marker='o', color='tomato', linewidth=2)

plt.title("本周气温变化", fontsize=16)
plt.xlabel("日期", fontsize=12)
plt.ylabel("温度 (°C)", fontsize=12)
plt.grid(True, linestyle='--', alpha=0.7)  # 添加网格线

plt.show()

多条折线对比

import matplotlib.pyplot as plt

months = ["1月", "2月", "3月", "4月", "5月", "6月"]
beijing = [2, 5, 12, 20, 26, 30]
shanghai = [5, 7, 12, 18, 23, 28]
guangzhou = [14, 15, 18, 23, 27, 30]

plt.figure(figsize=(10, 6))
plt.plot(months, beijing, marker='o', label="北京")
plt.plot(months, shanghai, marker='s', label="上海")
plt.plot(months, guangzhou, marker='^', label="广州")

plt.title("三城市上半年气温对比", fontsize=16)
plt.xlabel("月份", fontsize=12)
plt.ylabel("温度 (°C)", fontsize=12)
plt.legend(fontsize=12)  # 显示图例
plt.grid(True, linestyle='--', alpha=0.5)

plt.show()

柱状图

import matplotlib.pyplot as plt

# 编程语言受欢迎程度
languages = ["Python", "JavaScript", "Java", "C++", "Go"]
popularity = [35, 25, 20, 12, 8]
colors = ['#3776AB', '#F7DF1E', '#ED8B00', '#00599C', '#00ADD8']

plt.figure(figsize=(10, 6))
bars = plt.bar(languages, popularity, color=colors, edgecolor='white', width=0.6)

# 在柱子上方显示数值
for bar in bars:
    height = bar.get_height()
    plt.text(bar.get_x() + bar.get_width() / 2., height + 0.5,
             f'{height}%', ha='center', fontsize=12)

plt.title("2024年编程语言受欢迎程度", fontsize=16)
plt.xlabel("编程语言", fontsize=12)
plt.ylabel("占比 (%)", fontsize=12)
plt.ylim(0, 40)  # 设置y轴范围

plt.show()

分组柱状图

import matplotlib.pyplot as plt
import numpy as np

# 两个学期的成绩对比
subjects = ["语文", "数学", "英语", "物理", "化学"]
semester1 = [85, 78, 92, 70, 75]
semester2 = [88, 85, 90, 80, 82]

x = np.arange(len(subjects))  # 标签位置
width = 0.35  # 柱子宽度

plt.figure(figsize=(10, 6))
bars1 = plt.bar(x - width/2, semester1, width, label='上学期', color='steelblue')
bars2 = plt.bar(x + width/2, semester2, width, label='下学期', color='coral')

plt.title("两学期成绩对比", fontsize=16)
plt.xlabel("科目", fontsize=12)
plt.ylabel("分数", fontsize=12)
plt.xticks(x, subjects)
plt.legend(fontsize=12)
plt.ylim(60, 100)

plt.show()

饼图

import matplotlib.pyplot as plt

# 时间分配
activities = ["学习", "睡觉", "娱乐", "运动", "吃饭", "其他"]
hours = [8, 7, 3, 2, 2, 2]
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff66b3', '#c2c2f0']
explode = (0.05, 0, 0, 0, 0, 0)  # 突出显示"学习"

plt.figure(figsize=(8, 8))
plt.pie(hours, labels=activities, colors=colors, explode=explode,
        autopct='%1.1f%%', startangle=90, textprops={'fontsize': 12})

plt.title("一天时间分配", fontsize=16)
plt.axis('equal')  # 保证是正圆

plt.show()

散点图

import matplotlib.pyplot as plt
import numpy as np

# 模拟身高体重数据
np.random.seed(42)
height = np.random.normal(170, 8, 100)  # 100个人的身高
weight = height * 0.6 + np.random.normal(0, 5, 100)  # 体重和身高有相关性

plt.figure(figsize=(10, 6))
plt.scatter(height, weight, alpha=0.6, c='steelblue', edgecolors='white', s=60)

plt.title("身高与体重的关系", fontsize=16)
plt.xlabel("身高 (cm)", fontsize=12)
plt.ylabel("体重 (kg)", fontsize=12)
plt.grid(True, linestyle='--', alpha=0.5)

plt.show()

直方图

import matplotlib.pyplot as plt
import numpy as np

# 模拟考试成绩分布
np.random.seed(42)
scores = np.random.normal(75, 10, 200)  # 200个学生,均值75,标准差10

plt.figure(figsize=(10, 6))
plt.hist(scores, bins=20, color='steelblue', edgecolor='white', alpha=0.7)

plt.title("考试成绩分布", fontsize=16)
plt.xlabel("分数", fontsize=12)
plt.ylabel("人数", fontsize=12)
plt.axvline(x=np.mean(scores), color='red', linestyle='--', label=f'平均分: {np.mean(scores):.1f}')
plt.legend(fontsize=12)

plt.show()

子图(多图组合)

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 2 * np.pi, 100)

fig, axes = plt.subplots(2, 2, figsize=(12, 8))

# 左上:正弦
axes[0, 0].plot(x, np.sin(x), color='steelblue')
axes[0, 0].set_title("sin(x)")
axes[0, 0].grid(True, alpha=0.3)

# 右上:余弦
axes[0, 1].plot(x, np.cos(x), color='coral')
axes[0, 1].set_title("cos(x)")
axes[0, 1].grid(True, alpha=0.3)

# 左下:正切(限制范围)
axes[1, 0].plot(x, np.sin(x) ** 2, color='green')
axes[1, 0].set_title("sin²(x)")
axes[1, 0].grid(True, alpha=0.3)

# 右下:组合
axes[1, 1].plot(x, np.sin(x), label='sin(x)')
axes[1, 1].plot(x, np.cos(x), label='cos(x)')
axes[1, 1].set_title("sin(x) & cos(x)")
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3)

plt.tight_layout()  # 自动调整间距
plt.show()

seaborn进阶可视化

seaborn是基于matplotlib的高级封装,用更少的代码画出更好看的图。

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# 设置seaborn风格
sns.set_theme(style="whitegrid")

# 创建示例数据
np.random.seed(42)
data = pd.DataFrame({
    "月份": list(range(1, 13)) * 3,
    "销售额": np.random.randint(100, 500, 36),
    "城市": ["北京"] * 12 + ["上海"] * 12 + ["广州"] * 12
})

plt.figure(figsize=(10, 6))
sns.lineplot(data=data, x="月份", y="销售额", hue="城市", marker='o')
plt.title("各城市月度销售额", fontsize=16)

plt.show()

热力图

import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# 模拟各科目之间的相关性
subjects = ["语文", "数学", "英语", "物理", "化学", "生物"]
np.random.seed(42)
data = np.random.rand(6, 6)
# 让矩阵对称,模拟相关系数
data = (data + data.T) / 2
np.fill_diagonal(data, 1)

df = pd.DataFrame(data, index=subjects, columns=subjects)

plt.figure(figsize=(8, 6))
sns.heatmap(df, annot=True, fmt='.2f', cmap='coolwarm',
            vmin=0, vmax=1, linewidths=0.5)
plt.title("各科目成绩相关性", fontsize=16)

plt.show()

箱线图

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# 模拟不同班级的成绩
np.random.seed(42)
data = pd.DataFrame({
    "成绩": np.concatenate([
        np.random.normal(75, 10, 50),
        np.random.normal(80, 8, 50),
        np.random.normal(70, 12, 50)
    ]),
    "班级": ["一班"] * 50 + ["二班"] * 50 + ["三班"] * 50
})

plt.figure(figsize=(8, 6))
sns.boxplot(data=data, x="班级", y="成绩", palette="Set2")
plt.title("各班级成绩分布", fontsize=16)

plt.show()

保存图表

import matplotlib.pyplot as plt

plt.plot([1, 2, 3], [4, 5, 6])
plt.title("示例图表")

# 保存为不同格式
plt.savefig("chart.png", dpi=300, bbox_inches='tight')  # PNG格式,高清
plt.savefig("chart.pdf", bbox_inches='tight')            # PDF格式,矢量图
plt.savefig("chart.svg", bbox_inches='tight')            # SVG格式,网页用

# bbox_inches='tight' 会去掉多余的空白边距
# dpi=300 设置分辨率,适合打印

plt.show()

实战:用一份数据画完整报告

import matplotlib.pyplot as plt
import numpy as np

# 模拟电商数据
np.random.seed(42)
months = [f"{i}月" for i in range(1, 13)]
revenue = np.random.randint(50, 150, 12)  # 月收入(万元)
orders = np.random.randint(500, 2000, 12)  # 订单数
categories = ["电子产品", "服装", "食品", "家居", "图书"]
category_sales = [35, 25, 20, 12, 8]

fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle("2024年电商数据分析报告", fontsize=18, fontweight='bold')

# 左上:月收入趋势
axes[0, 0].plot(months, revenue, marker='o', color='steelblue', linewidth=2)
axes[0, 0].fill_between(range(12), revenue, alpha=0.1, color='steelblue')
axes[0, 0].set_title("月收入趋势", fontsize=14)
axes[0, 0].set_ylabel("收入(万元)")
axes[0, 0].tick_params(axis='x', rotation=45)
axes[0, 0].grid(True, alpha=0.3)

# 右上:月订单量
axes[0, 1].bar(months, orders, color='coral', edgecolor='white')
axes[0, 1].set_title("月订单量", fontsize=14)
axes[0, 1].set_ylabel("订单数")
axes[0, 1].tick_params(axis='x', rotation=45)

# 左下:品类占比
axes[1, 0].pie(category_sales, labels=categories, autopct='%1.1f%%',
               colors=['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#c2c2f0'])
axes[1, 0].set_title("品类销售占比", fontsize=14)

# 右下:收入与订单的关系
axes[1, 1].scatter(orders, revenue, c='steelblue', alpha=0.7, s=80, edgecolors='white')
axes[1, 1].set_title("订单量与收入关系", fontsize=14)
axes[1, 1].set_xlabel("订单数")
axes[1, 1].set_ylabel("收入(万元)")
axes[1, 1].grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig("ecommerce_report.png", dpi=300, bbox_inches='tight')
plt.show()

更多推荐