Python 基础
Dec 26, 2024
Python 是一种功能强大且易于学习的编程语言,它在人工智能、Web 开发、数据分析等领域都有着广泛的应用。本教程旨在帮助零基础的读者快速入门 Python 编程。
为什么选择 Python?
- 简洁易读: Python 语法清晰简洁,接近自然语言,易于理解和学习。
 - 应用广泛: 从人工智能、机器学习到 Web 开发、数据科学,Python 无处不在。
 - 强大的库支持: Python 拥有海量的标准库和第三方库,可以轻松完成各种任务。
 - 社区活跃: 庞大的 Python 社区提供了丰富的学习资源和技术支持。
 
Python 在人工智能领域的应用 (包括但不限于):
- 文本到图像生成 (Text to Images)
 - 大型语言模型 (LLMs)
 - 深度学习 (Deep Learning)
 
知名公司都在使用 Python:
- Tesla (特斯拉): 使用 OpenCV 进行计算机视觉应用开发。
 - Instagram (照片墙): 采用 Django 框架构建 Web 应用。
 
Python 的应用场景
- 人工智能 (AI) & 机器学习 (ML)
 - 计算机视觉 (Computer Vision)
 - Web 应用程序开发 (Web Applications): 例如 Flask, Django 等框架。
 - 数据分析与可视化 (Data Analytics and Visualization)
 - 自动化脚本 (Automation Scripts)
 - 科学计算 (Scientific Computing)
 
基础语法
变量 (Variables)
变量是用于存储数据值的容器。在 Python 中,变量无需声明类型,直接赋值即可。
a = 1       # 整型变量
b = False   # 布尔型变量
c = "你好"   # 字符串变量 (中文 Unicode 字符)
d = None    # NoneType 空值
数据类型 (Data Types)
Python 提供了多种内置数据类型:
- 
数字 (Number): 用于表示数值。
- 整型 (int):  整数,例如 
3,-8,0 - 浮点型 (float): 小数,例如 
3.8,0.001,-9.0 - 复数 (complex): 复数,例如 
2 + 3j,可以使用complex(实部, 虚部)创建,例如a = complex(123, 2)#123 + 2j 
 - 整型 (int):  整数,例如 
 - 
文本 (Text): 用于表示文本信息。
- 字符串 (str):  文本序列,使用单引号 
'或双引号"括起来,例如"Hello World",'Python 教程' 
 - 字符串 (str):  文本序列,使用单引号 
 - 
布尔值 (Boolean): 用于表示真假。
True(真) 或False(假)
 - 
序列 (Sequence): 有序的数据集合。
- 
列表 (list): 可变的有序集合,元素用逗号分隔,方括号
[]括起来。list1 = [1, 2.3, [-4, 5], ['apple']] # 列表可以包含不同类型的元素 - 
元组 (tuple): 不可变的有序集合,元素用逗号分隔,圆括号
()括起来。tuple1 = (("张三", "李四"), ("王五", "赵六")) # 元组一旦创建就不能修改 - 
可变 (Mutable) vs 不可变 (Immutable):
- 可变数据类型 (如列表) 创建后可以修改其内容。
 - 不可变数据类型 (如元组、字符串、数字) 创建后内容不能直接修改,任何修改操作都会创建新的对象。
 
 
 - 
 - 
映射 (Mapping): 键值对集合。
- 
字典 (dictionary 或 dict): 无序的键值对集合,键值对之间用逗号分隔,花括号
{}括起来。dict1 = { "姓名": "张三", "年龄": 20, "性别": "男", "会编程": True } # 字典使用键值对存储数据 
注意: 在 Python 中,一切皆对象 (OBJECT)! 包括字典、数字、布尔值等。
 - 
 
运算符 (Operators)
运算符 (Operator)	运算符名称 (Operator Name)	示例 (Example)
+	加法 (Addition)	5 + 7
-	减法 (Subtraction)	5 - 7
*	乘法 (Multiplication)	5 * 7
/	除法 (Division)	5 / 7
%	取模 (Modulus)	5 % 7 (求余数)
//	地板除法 (Floor Division)	5 // 7 (向下取整)
**	幂运算 (Exponentiation)	5 ** 2 (5 的 2 次方)
类型转换 (Type Casting)
类型转换是将一个数据类型的值转换为另一个数据类型的过程。Python 中称为类型转换 (Type Conversion)。
常用类型转换函数:
int(): 转换为整型float(): 转换为浮点型str(): 转换为字符串ord(): 返回字符的 Unicode 代码点hex(): 转换为十六进制字符串oct(): 转换为八进制字符串tuple(): 转换为元组list(): 转换为列表set(): 转换为集合dict(): 转换为字典
类型转换方式:
- 显式转换 (Explicit Conversion): 开发者手动进行类型转换。
 - 隐式转换 (Implicit Conversion): Python 自动进行的类型转换。
 
显式转换示例:
a = "1"  # 字符串类型
b = "2"
print(int(a) + int(b))  # 将字符串转换为整型后再相加,输出 3
隐式转换示例:
c = 1.9  # 浮点型
d = 8     # 整型
print(c + d) # d 会被隐式转换为浮点型,输出 9.9
用户输入 (Taking User Input)
使用 input() 函数获取用户输入,该函数返回的始终是 字符串 类型。
x = input("请输入第一个数字: ") # 提示用户输入
y = input("请输入第二个数字: ")
print(x + y) # 字符串拼接,例如输入 12 和 100,输出 12100
要进行数值运算,需要将输入的字符串转换为数值类型:
print(int(x) + int(y))  # 类型转换后相加,例如输入 12 和 100,输出 112
字符串操作 (String Handling)
字符串 (Strings) 是文本数据的序列,使用单引号或双引号括起来。
访问字符 (Accessing Characters)
字符串可以像数组一样通过索引访问字符,索引从 0 开始。
name = "张三"
print(name[0])  # 输出: '张'
print(name[1])  # 输出: '三'
字符串切片 (String Slicing)
切片用于提取字符串的一部分。
fruit = "苹果"
length = len(fruit) # len() 函数获取字符串长度
print("“", fruit, "” 是一个", length, "个字的词") # 输出: “ 苹果 ” 是一个 2 个字的词
pie = "苹果派"
print(pie[:2])  # 输出: '苹果' (从开始到索引 2 之前,不包含索引 2)
print(pie[2])   # 输出: '派' (索引为 2 的字符)
字符串方法 (String Methods)
Python 字符串对象提供了丰富的方法,用于字符串操作。
- 
upper(): 转换为大写。str_example = "HelloWorld" print(str_example.upper()) # 输出: 'HELLOWORLD' - 
lower(): 转换为小写。 - 
strip(): 去除字符串首尾的空白字符 (空格、制表符、换行符等)。str_example = " 空格很多 " print(str_example.strip()) # 输出: '空格很多' - 
rstrip(): 去除字符串尾部的指定字符。str_example = "hello!!!" print(str_example.rstrip("!")) # 输出: 'hello' - 
replace(old, new): 将字符串中所有出现的old子串替换为new子串。str_example = "香蕉苹果" print(str_example.replace("苹果", "梨子")) # 输出: '香蕉梨子' - 
split(sep): 根据分隔符sep将字符串分割成列表。str_example = "苹果 香蕉 橘子" print(str_example.split(" ")) # 输出: ['苹果', '香蕉', '橘子'] - 
capitalize(): 将字符串的第一个字符转换为大写。 - 
center(width, fillchar): 将字符串居中,并使用fillchar填充两侧至指定宽度width。 - 
count(sub): 统计子串sub在字符串中出现的次数。str_example = "abracadabra" count_a = str_example.count("a") print(count_a) # 输出: 5 - 
endswith(suffix): 检查字符串是否以suffix结尾,返回True或False。 - 
find(sub): 查找子串sub在字符串中首次出现的索引,如果未找到则返回-1。str_example = "我的名字是张三,他也是。" print(str_example.find("是")) # 输出: 4 print(str_example.find("李四")) # 输出: -1注意:
index()方法与find()类似,但如果子串不存在,index()会抛出异常 (ValueError),而find()返回-1。 - 
isalnum(): 检查字符串是否只包含字母和数字字符,返回True或False。 - 
islower(): 检查字符串是否所有字符都是小写,返回True或False。 - 
isprintable(): 检查字符串是否所有字符都是可打印字符,返回True或False。 - 
isspace(): 检查字符串是否只包含空白字符,返回True或False。 - 
istitle(): 检查字符串是否是标题格式 (每个单词首字母大写),返回True或False。 - 
isupper(): 检查字符串是否所有字符都是大写,返回True或False。 
条件语句 (Conditional Statements)
if: 基本条件判断。if-else: 条件成立和不成立时分别执行不同的代码块。if-elif-else: 多条件判断。- 嵌套 
if-elif-else: 条件语句内部再嵌套条件语句。 
if 语句示例
iphone_price = 60000
budget = 20000
if budget < iphone_price:
    print("预算不足,再攒攒钱吧!") # 如果预算小于 iPhone 价格,则输出
else:
    print("可以买个 iPhone 啦!") # 否则输出
elif 语句示例
number = 0
if number < 0:
    print("数字是负数")
elif number == 0:
    print("数字是零")
else:
    print("数字是正数")
嵌套 if 语句示例
number = 18
if number < 0:
    print("数字是负数")
elif number > 0:
    if number <= 10:
        print("数字在 1 到 10 之间")
    elif number > 10 and number <= 20:
        print("数字在 11 到 20 之间")
    else:
        print("数字大于 20")
else:
    print("数字是零")
# 输出: 数字在 11 到 20 之间
条件运算符 (Conditional Operators)
条件运算符用于比较值。
- 运算符: 
>(大于),<(小于),>=(大于等于),<=(小于等于),==(等于),!=(不等于) 
a = 18
print(a > 18)   # 输出: False
print(a <= 18)  # 输出: True
print(a == 18)  # 输出: True
print(a != 18)  # 输出: False
循环语句 (Loops)
for 循环 (For Loops)
for 循环用于遍历可迭代对象 (Iterable objects),例如字符串、列表、元组、集合、字典等。
- 
遍历字符串示例:
name = "Martin" for char in name: print(char, end=", ") # end=", " 表示每次打印后以逗号和空格结尾,而不是默认的换行符 # 输出: M, a, r, t, i, n, - 
遍历列表示例:
colors = ["红色", "绿色", "蓝色"] for color in colors: print(color) for letter in color: print(letter) - 
使用
range()函数生成数字序列:for k in range(1, 200): # range(start, stop) 生成从 start 到 stop-1 的整数序列 print(k) # 输出: 从 1 到 199 的数字for k in range(2, 12, 2): # range(start, stop, step) step 为步长 print(k) # 输出: 2, 4, 6, 8, 10 
while 循环 (While Loop)
while 循环在条件为 True 时重复执行代码块。
count = 5
while count > 0:
    print(count)
    count -= 1 # 每次循环 count 减 1
else:
    print("循环结束,进入 else 块") # 当 while 循环条件变为 False 时,会执行 else 块 (可选)
break 和 continue 语句 (Break & Continue)
- 
break: 立即跳出循环,终止循环的执行。 - 
continue: 跳过当前循环迭代的剩余代码,直接进入下一次迭代。 - 
break语句示例:for i in range(1, 101): print(i, end=" ") if i == 50: break # 当 i 等于 50 时,跳出循环 else: print("继续循环") # 输出: 1 继续循环 2 继续循环 ... 49 继续循环 50 - 
continue语句示例:for i in range(12): if i == 10: print("跳过本次迭代") continue # 当 i 等于 10 时,跳过本次循环的剩余代码 print("5 x", i, "=", 5 * i) # 输出: 5 x 0 = 0 ... 5 x 9 = 45 跳过本次迭代 5 x 11 = 55 
函数 (Python Functions)
函数是一段组织好的、可重复使用的代码块,用于执行特定任务。函数可以提高代码的模块化和可重用性。
- 
内置函数 (Built-in Functions): Python 提供的预定义函数,例如
min(),max(),len(),sum(),type(),tuple(),list(),set(),print(),range(),dict()等。 - 
用户自定义函数 (User-Defined Functions): 开发者根据需求定义的函数。
用户自定义函数示例:
def greet(first_name, last_name): # 定义函数 greet,接收两个参数 print("你好,", first_name, last_name) greet("三", "张") # 调用函数,传入参数 
函数参数 (Function Arguments)
- 
默认参数 (Default Arguments): 在定义函数时为参数设置默认值。
def greet(first_name, middle_name="某某", last_name="先生"): # middle_name 和 last_name 设置了默认值 print("你好,", first_name, middle_name, last_name) greet("李") # 输出: 你好, 李 某某 先生 (middle_name 和 last_name 使用默认值) - 
关键字参数 (Keyword Arguments): 在调用函数时使用
参数名=值的形式传递参数,可以不按参数顺序传递。def greet(first_name, middle_name, last_name): print("你好,", first_name, middle_name, last_name) greet(middle_name="彼得", last_name="韦斯克", first_name="杰登") # 使用关键字参数,顺序可以改变 # 输出: 你好, 杰登 彼得 韦斯克 - 
必需参数 (Required Arguments): 在函数定义中没有默认值的参数,调用时必须提供值。
# 调用 greet("张三", "先生") 会报错,因为缺少 last_name 参数 # greet("张三", "先生") # TypeError: greet() missing 1 required positional argument: 'last_name' - 
可变长度参数 (Variable-Length Arguments): 允许函数接收不定数量的参数。
- 
*任意位置参数 (Arbitrary Arguments - args): 使用
*前缀,将传入的位置参数打包成元组。def greet(*names): # *names 将接收到的所有位置参数打包成元组 names print("你好,", names[0], names[1], names[2]) greet("张三", "李四", "王五") - 
**任意关键字参数 (Arbitrary Keyword Arguments - kwargs): 使用
**前缀,将传入的关键字参数打包成字典。def greet(**names): # **names 将接收到的所有关键字参数打包成字典 names print(names["first_name"], names["middle_name"], names["last_name"]) greet(first_name="张", middle_name="小", last_name="三") 
 - 
 - 
return语句 (Return Statement): 函数可以使用return语句返回值给调用者。def add(a, b): return a + b # 返回 a + b 的结果 result = add(5, 3) print(result) # 输出: 8 
列表 (List)
列表 (List) 是 Python 中常用的数据结构,它是一个 有序 且 可变 的元素集合。列表中的元素可以是不同的数据类型。
- 
列表示例:
list1 = [1, 2, 3, 4, 5, 6] list2 = ["红色", "绿色", "蓝色"] details = ["张三", 20, "计算机科学"] 
检查元素是否在列表中:使用
in关键字。
colors = ["红色", "绿色", "蓝色", "黄色"]
if "黄色" in colors:
    print("黄色在列表中")
列表索引范围 (Range of Index)
可以使用索引访问列表的不同部分:
- 
打印从指定索引到末尾的所有元素:
animals = ["猫", "狗", "蝙蝠", "狮子", "老虎", "山羊", "牛"] print(animals[4:]) # 从索引 4 开始到末尾 - 
打印从开始到指定索引之前的所有元素:
print(animals[:6]) # 从开始到索引 6 之前 - 
打印间隔取值的元素 (步长为 2):
print(animals[::2]) # 从开始到末尾,步长为 2 - 
在指定范围内,每隔 3 个元素取一个:
print(animals[1:8:3]) # 从索引 1 到 8 之前,步长为 3 
列表推导式 (List Comprehension)
列表推导式提供了一种简洁的方式来创建列表,可以从其他可迭代对象 (如列表、元组、字典、集合,甚至字符串) 创建新列表。
- 
示例 1: 筛选包含字母 "o" 的元素:
names = ["Milo", "Sarah", "Bruno", "Anastasia", "Rose"] names_with_o = [item for item in names if "o" in item] # 列表推导式,筛选包含 "o" 的名字 print(names_with_o) # 输出: ['Milo', 'Bruno', 'Rose'] - 
示例 2: 筛选长度大于 4 的元素:
names_with_4_letters = [item for item in names if len(item) > 4] # 列表推导式,筛选长度大于 4 的名字 print(names_with_4_letters) # 输出: ['Sarah', 'Bruno', 'Anastasia'] 
列表方法 (List Methods)
以下是一些常用的列表方法:
- 
list.sort(): 对列表进行升序排序 (默认)。colors = ["紫色", "靛蓝", "蓝色", "绿色"] colors.sort() # 升序排序 print(colors) # 输出: ['蓝色', '绿色', '靛蓝', '紫色']降序排序:
numbers = [4, 5, 1, 2, 3, 6, 7, 9, 8] numbers.sort(reverse=True) # 降序排序 print(numbers) # 输出: [9, 8, 7, 6, 5, 4, 3, 2, 1] - 
list.reverse(): 反转列表中的元素顺序。colors.reverse() # 反转列表 print(colors) # 输出 (基于之前的排序结果): ['紫色', '靛蓝', '绿色', '蓝色'] - 
list.index(item): 返回列表中第一个匹配项item的索引。index_green = colors.index("绿色") print(index_green) # 输出: 2 (假设列表为 ['紫色', '靛蓝', '绿色', '蓝色']) - 
list.count(item): 返回列表中item出现的次数。count_green = colors.count("绿色") print(count_green) # 输出: 1 (假设列表为 ['紫色', '靛蓝', '绿色', '蓝色']) - 
list.copy(): 返回列表的浅拷贝。- 用于在不修改原始列表的情况下,对列表副本进行操作。
 
copy_colors = colors.copy() # 创建 colors 列表的副本 - 
list.append(item): 将item添加到列表末尾。colors = ["紫色", "靛蓝"] colors.append("蓝色") # 添加 "蓝色" 到列表末尾 print(colors) # 输出: ['紫色', '靛蓝', '蓝色'] - 
list.insert(index, item): 在指定索引index处插入item。colors = ["紫色", "靛蓝"] colors.insert(1, "绿色") # 在索引 1 处插入 "绿色" print(colors) # 输出: ['紫色', '绿色', '靛蓝'] - 
list.extend(iterable): 将另一个可迭代对象iterable(如列表、元组) 中的元素添加到列表末尾。colors = ["紫", "靛", "蓝"] rainbow = ["绿", "黄", "橙", "红"] colors.extend(rainbow) # 将 rainbow 列表中的元素添加到 colors 列表末尾 print(colors) # 输出: ['紫', '靛', '蓝', '绿', '黄', '橙', '红'] - 
列表连接 (Concatenating Two Lists):
color1 = ["红", "橙"] color2 = ["黄", "绿"] combined_list = color1 + color2 # 使用 + 运算符连接两个列表 print(combined_list) # 输出: ['红', '橙', '黄', '绿'] 
元组 (Tuples)
- 
元组 (Tuple) 也是 有序 的数据集合,类似于列表,但元组是 不可变 的 (immutable),即创建后不能修改。
tuple1 = (1, 2, 2, 3, 4, 5, 6) tuple2 = ("红色", "绿色", "蓝色") details = ("张三", 19, "计算机科学", 9.7)- 
元组索引 (Tuple Indexes):
- 元组中的每个元素都有自己的索引,索引从 0 开始。
 country = ("中国", "意大利", "西班牙")[0] [1] [2]country[0]# -> "中国"
 - 
检查元素是否在元组中使用
in关键字: 
 - 
 
country = ("中国", "意大利", "西班牙")
if "中国" in country:
   print("中国在元组中")
操作元组 (Manipulating Tuples)
- 
由于元组是不可变的,如果需要添加、删除或修改元组中的元素,需要先将元组转换为 列表 (list)。
 - 
元组转换为列表 (Tuple to List Conversion):
countries = ("意大利", "中国", "英国") temp_list = list(countries) # 将元组转换为列表 temp_list.append("德国") # 列表可以添加元素 temp_list.pop(1) # 列表可以删除元素 (删除索引 1 的元素) temp_list[2] = "芬兰" # 列表可以修改元素 countries = tuple(temp_list) # 将列表转换回元组 print(countries) 
注意: 可以直接连接两个元组,无需转换为列表。
countries1 = ("中国",) # 注意,只有一个元素的元组,元素后要加逗号
countries2 = ("英国",)
print(countries1 + countries2) # 元组连接
# 输出: ('中国', '英国')
元组方法 (Tuple Methods)
- 
count(item): 返回元组中item出现的次数。tup1 = (1, 2, 3, 3, 3) print(tup1.count(3)) # 输出: 3 - 
index(item): 返回元组中第一个匹配项item的索引。tup1 = (1, 2, 3, 4) print(tup1.index(3)) # 输出: 2注意:
- 
tup1 = (1)创建的是整型变量,而不是元组。要创建只有一个元素的元组,需要使用tup2 = (1,)。tup1 = (1) print(type(tup1)) # 输出: <class 'int'> tup2 = (1,) print(type(tup2)) # 输出: <class 'tuple'> 
 - 
 
注意: 元组通常用于存储不应被修改的常量数据。
F-字符串 (F-Strings)
F-字符串 (Formatted String Literals) 提供了一种简洁的方式,在字符串字面值中嵌入表达式,使用花括号 {} 括起来。
name = "张三"
print(f"你好, {name}!") # 使用 f-字符串,直接在字符串中嵌入变量 name
Python 文档字符串 (Docstrings)
- 文档字符串 (Docstrings) 是字符串字面值,出现在函数、方法、类或模块定义的正文之后。
 - 它们用于为代码提供文档说明。
 
def square(n):
    '''计算数字 n 的平方并返回。''' # 文档字符串,描述函数功能
    return n**2
print(square(5)) # 输出:25
print(square.__doc__) # 访问函数的文档字符串,输出:计算数字 n 的平方并返回。
Python 注释 (Comments) vs. 文档字符串 (Docstrings)
- 
注释 (Comments): 用于解释代码,给人类阅读。Python 解释器会忽略注释。类似于你暗恋的人忽略你!
 - 
文档字符串 (Docstrings): 用于为函数、方法、类等编写文档。可以使用
__doc__属性访问文档字符串。print(square.__doc__) # 访问 square 函数的文档字符串 
PEP 8 代码规范 (PEP 8)
- PEP 8 是一份 Python 代码风格指南,提供了编写 Python 代码的最佳实践建议。
 - 旨在提高 Python 代码的可读性和一致性。
 - PEP: Python 增强提案 (Python Enhancement Proposal)
 
递归 (Recursion)
- 递归 (Recursion) 是一种定义事物的方式,其中该事物在其自身定义中被引用。
 - 函数可以调用其他函数,也可以调用自身。
 
def factorial(num):
   if (num == 1 or num == 0):
      return 1 # 递归基例:当 num 为 1 或 0 时,阶乘为 1
   else:
      return (num * factorial(num-1)) # 递归调用:factorial(num) 调用 factorial(num-1)
阶乘计算过程示例 (以 5! 为例):
factorial(5)
= 5 * factorial(4)
= 5 * 4 * factorial(3)
= 5 * 4 * 3 * factorial(2)
= 5 * 4 * 3 * 2 * factorial(1)
= 5 * 4 * 3 * 2 * 1  # factorial(1) 返回 1,递归结束
= 120
集合 (Sets)
- 集合 (Set) 是 无序 且 唯一 的元素集合。
 - 集合中的元素用逗号分隔,花括号 
{}括起来。 - 集合是 可变 的,但集合中的元素必须是 不可变 的数据类型 (例如,数字、字符串、元组)。
 - 集合 不包含重复元素。
 
info = {"张三", 20, False, 5.9} # 集合示例
print(info) # 输出的顺序可能与定义的顺序不同,因为集合是无序的
- 集合是无序的,因此不能使用索引访问元素。
 - 集合的应用场景:例如,在办公室检查哪些员工没有收到礼物,需要收集员工姓名,并去重。
 
集合操作: add, union, difference, intersection, update, intersection_update, symmetric_difference, discard (不报错), remove (报错)
集合的连接操作 (Joining operations in sets):
- 
union()和update(): 并集- 返回两个集合中所有元素的并集。
 update()方法将另一个集合的元素添加到现有集合中。
cities1 = {"东京", "马德里", "柏林", "德里"} cities2 = {"东京", "首尔", "喀布尔", "马德里"} cities3 = cities1.union(cities2) # 返回 cities1 和 cities2 的并集,创建新集合 cities3 print(cities3) # 输出: {'东京', '马德里', '柏林', '德里', '首尔', '喀布尔'} cities1.update(cities2) # 将 cities2 的元素添加到 cities1 中,修改 cities1 本身 print(cities1) # 输出: {'东京', '马德里', '柏林', '德里', '首尔', '喀布尔'} - 
intersection()和intersection_update(): 交集- 返回两个集合中共同的元素 (交集)。
 
cities3 = cities1.intersection(cities2) # 返回 cities1 和 cities2 的交集,创建新集合 cities3 print(cities3) # 输出: {"马德里", "东京"} cities1.intersection_update(cities2) # 将 cities1 更新为 cities1 和 cities2 的交集,修改 cities1 本身 print(cities1) # 输出: {"马德里", "东京"} - 
symmetric_difference()和symmetric_difference_update(): 对称差集- 返回两个集合中不相同的元素 (对称差集)。
 
cities1 = {"东京", "马德里", "柏林", "德里"} cities2 = {"东京", "首尔", "喀布尔", "马德里"} print(cities1.symmetric_difference(cities2)) # 返回 cities1 和 cities2 的对称差集,创建新集合 # 输出: {"首尔", "喀布尔", "柏林", "德里"} - 
difference()和difference_update(): 差集- 返回集合间的差集。例如 
cities1.difference(cities2)返回cities1中存在,但cities2中不存在的元素。 
 - 返回集合间的差集。例如 
 
集合方法 (Set methods):
- 
isdisjoint(other_set):- 检查当前集合与 
other_set是否不相交 (没有共同元素)。 - 如果不相交,返回 
True,否则返回False。 
cities1 = {"东京", "马德里"} cities2 = {"首尔", "喀布尔"} is_disjoint = cities1.isdisjoint(cities2) print(is_disjoint) # 输出: True (因为 cities1 和 cities2 没有共同元素) - 检查当前集合与 
 - 
issuperset(other_set):- 检查当前集合是否是 
other_set的超集 (包含other_set的所有元素)。 - 如果是超集,返回 
True,否则返回False。 
cities1 = {"东京", "马德里", "柏林"} cities2 = {"东京", "马德里"} is_superset = cities1.issuperset(cities2) print(is_superset) # 输出: True (因为 cities1 包含 cities2 的所有元素) - 检查当前集合是否是 
 - 
issubset(other_set): 检查当前集合是否是other_set的子集。 - 
add(item): 向集合中添加元素item。cities1 = {"东京", "马德里"} cities1.add("赫尔辛基") # 向 cities1 集合添加 "赫尔辛基" 元素 print(cities1) # 输出 (顺序可能不同): {'东京', '马德里', '赫尔辛基'} - 
update(other_set): 将另一个集合other_set中的元素添加到当前集合。cities1 = {"东京", "马德里"} cities2 = {"柏林", "首尔"} cities1.update(cities2) # 将 cities2 的元素添加到 cities1 print(cities1) # 输出 (顺序可能不同): {'东京', '马德里', '柏林', '首尔'} - 
remove(item)/discard(item): 从集合中删除元素item。- 
remove(item): 如果元素item不存在,会抛出 KeyError 错误。cities1 = {"东京", "马德里"} cities1.remove("东京") # 删除 "东京" 元素 print(cities1) # 输出: {'马德里'} # cities1.remove("北京") # 如果 "北京" 不在 cities1 中,会抛出 KeyError 错误 - 
discard(item): 如果元素item不存在,不会报错,安全删除。cities2 = {"东京", "首尔"} cities2.discard("东京") # 删除 "东京" 元素 print(cities2) # 输出: {'首尔'} cities2.discard("北京") # 如果 "北京" 不在 cities2 中,不会报错 
 - 
 - 
pop(): 随机删除并返回集合中的一个元素。由于集合是无序的,所以删除的是“随机”的元素。 - 
del set_name: 删除整个集合。 - 
clear(): 清空集合中的所有元素,集合变为空集。 
字典 (Python Dictionaries)
- 字典 (Dictionary) 是 Python 中的 有序 (Python 3.7+ 版本开始有序) 键值对集合。
 - 字典用于存储 键 (Key) - 值 (Value) 对,键必须是 唯一 且 不可变 的数据类型 (例如,字符串、数字、元组),值可以是任意数据类型。
 - 字典中的键值对用逗号分隔,花括号 
{}括起来。 
info = {"姓名": "张三", "年龄": 19, "语言": "Python"} # 字典示例
- 
访问单个值 (Accessing single values):
name = info['姓名'] # 使用键 '姓名' 访问对应的值 print(name) # 输出: '张三' language = info.get('语言') # 使用 get() 方法,更安全,如果键不存在返回 None 或默认值 print(language) # 输出: 'Python' - 
访问多个值和键 (Access multiple values and keys):
values = info.values() # 获取字典中所有值的视图对象 print(values) # 输出: dict_values(['张三', 19, 'Python']) keys = info.keys() # 获取字典中所有键的视图对象 print(keys) # 输出: dict_keys(['姓名', '年龄', '语言']) - 
访问键值对 (Access key-value pairs): 使用
items()方法遍历键值对。for key, value in info.items(): # items() 方法返回键值对的视图对象 print(f"{key}: {value}") # 使用 f-字符串格式化输出 # 输出: # 姓名: 张三 # 年龄: 19 # 语言: Python 
字典方法 (Dictionary methods):
ep1 = {122: 45, 123: 89, 567: 69, 670: 69}
ep2 = {222: 67, 566: 90}
ep1.update(ep2) # 将 ep2 中的键值对添加到 ep1 中,如果键已存在则更新值
print(ep1) # 输出: {122: 45, 123: 89, 567: 69, 670: 69, 222: 67, 566: 90}
ep1.clear() # 清空字典 ep1
print(ep1) # 输出: {}
ep1 = {122: 45, 123: 89}
removed_value = ep1.pop(122) # 删除键为 122 的键值对,并返回对应的值 45
print(ep1) # 输出: {123: 89}
print(removed_value) # 输出: 45
ep1 = {122: 45, 123: 89}
removed_item = ep1.popitem() # 删除并返回字典的最后一个键值对 (Python 3.7+ 版本中字典是有序的,删除的是最后添加的)
print(ep1) # 输出: {122: 45} (假设 123: 89 是最后添加的)
print(removed_item) # 输出: (123, 89)
ep1 = {122: 45, 123: 89}
del ep1[122] # 删除键为 122 的键值对
print(ep1) # 输出: {123: 89}
- 
update(other_dict): 更新字典,将other_dict中的键值对添加到当前字典。如果键已存在,则更新值;如果键不存在,则添加新的键值对。info = {'年龄': 19} info.update({'年龄': 20}) # 更新键 '年龄' 的值,19 -> 20 print(info) # 输出: {'年龄': 20} info.update({'出生年份': 2003}) # 添加新的键值对 '出生年份': 2003 print(info) # 输出: {'年龄': 20, '出生年份': 2003} - 
clear(): 清空字典中的所有键值对,使字典变为空字典。 - 
pop(key): 删除指定键key的键值对,并返回对应的值。如果键不存在,会抛出 KeyError 错误。 - 
popitem(): 删除并返回字典的最后一个键值对 (Python 3.7+ 版本中字典是有序的,删除的是最后添加的)。 - 
del dict[key]: 删除指定键key的键值对。也可以使用del dict_name删除整个字典。注意:
del dict[key]和pop(key)的区别:pop(key)会返回被删除的值! 
for...else 循环 (For loop with else)
for x in range(5):
   print(f"{x} 数字")
else:
   print("for 循环结束,进入 else 块") # for 循环正常结束后,执行 else 块
x = 0
while x < 7:
   print(x)
   x += 1
else:
   print("while 循环结束,进入 else 块") # while 循环条件变为 False 后,执行 else 块
else块出现在循环体之后。else块在循环正常结束 (即,不是通过break语句跳出循环) 后执行。- 程序只有在循环的所有迭代都完成后才会退出循环并执行 
else块。 
异常处理 (Exception Handling)
try:
   num = int(input("请输入一个整数: "))
   a = [6, 3]
   print(a[num]) # 尝试访问列表 a 的索引 num 的元素
except IndexError:
   print("索引错误: 列表索引超出范围") # 捕获 IndexError 异常
except ValueError:
    print("值错误:输入的不是整数") # 捕获 ValueError 异常
a_str = input("请输入一个数字: ")
print(f"{a_str} 的乘法表是:")
try:
   a = int(a_str)
   for i in range(1, 11):
       print(f"{a} x {i} = {a * i}")
except ValueError:
   print("无效输入:请输入有效的数字") # 捕获 ValueError 异常,处理非数字输入的情况
- 异常处理是一种处理程序运行时错误 (异常) 的机制。
 - 避免程序因错误而崩溃。
 
finally 子句 (Finally clause)
finally 子句用于定义无论是否发生异常都 始终 执行的代码块 (例如,关闭文件、关闭数据库连接、程序结束时输出提示信息)。
使用 finally 示例:
try:
    result = 10 / 0 # 可能会抛出 ZeroDivisionError 异常
except ZeroDivisionError:
    print("不能除以零。") # 捕获 ZeroDivisionError 异常并处理
finally:
    print("finally 块总是会被执行。") # finally 块中的代码始终会被执行
在这个例子中:
- 如果发生异常 (例如,除以零),
except块会处理异常。 - 无论是否发生异常,
finally块都会被执行。这确保了清理代码或重要的最后步骤始终能够执行。 
不使用 finally 的情况:
try:
    result = 10 / 0
except ZeroDivisionError:
    print("不能除以零。")
# 没有 `finally` 块,如果发生异常,这行代码可能不会执行
print("如果发生异常,这行代码可能不会执行。")
在这种情况下,try-except 块之后的代码 (print("如果发生异常,这行代码可能不会执行。")) 只有在 没有 异常抛出时才会执行。如果捕获到异常,except 块之后的代码不会被执行。
自定义异常 (Custom Errors)
a = int(input("请输入 5 到 9 之间的值: "))
if a < 5 or a > 9:
   raise ValueError("值应该在 5 到 9 之间 :)") # 使用 raise 关键字抛出自定义 ValueError 异常
- 使用 
raise关键字创建和抛出自定义异常。 - 当需要在特定异常发生时执行特定操作时很有用 (例如,发送错误报告给管理员、调用 API 等)。
 
简写 if-else 语句 (Short-hand if-else):
a = 330000
b = 3303
print("A") if a > b else print("=") if a == b else print("B") # 简写 if-elif-else 结构
c = 9 if a > b else 0 # 基于条件赋值
result = value_if_true if condition else value_if_false # 通用简写 if-else 结构
- 用于简单的 
if-else语句,特别是在需要根据条件为变量赋值时。 
enumerate() 函数 (Enumerate)
marks = [12, 56, 32, 98, 12, 45, 1, 4]
index = 0
for mark in marks:
   print(mark)
   if index == 3:
      print("真棒!")
   index += 1
for index, mark in enumerate(marks, start=1): # enumerate() 函数同时返回索引和值,start=1 指定索引起始值
   print(index, mark)
   if index == 3:
      print("真棒!")
enumerate()函数允许在遍历序列 (列表、元组、字符串) 时,同时获取元素的索引和值。- 当需要同时操作索引和值时非常有用。
 
fruits = ['苹果', '香蕉', '芒果']
for index, fruit in enumerate(fruits, start=1): # 索引从 1 开始
   print(index, fruit)
# 输出:
1 苹果
2 香蕉
3 芒果
虚拟环境 (Virtual Environment)
- 
虚拟环境 (Virtual Environment) 用于隔离 Python 项目的依赖环境,以便在同一台机器上开发多个项目,避免不同项目之间包版本冲突。
 - 
例如:项目 1 使用 OpenCV 版本 4.9.0,而另一个项目使用 OpenCV 版本 4.5。
 - 
常用命令:
python -m venv env # 创建名为 env 的虚拟环境 env/scripts/activate # (Windows) 激活虚拟环境 source env/bin/activate # (macOS/Linux) 激活虚拟环境 pip freeze > requirements.txt # 将当前环境的包列表导出到 requirements.txt 文件 pip install -r requirements.txt # 从 requirements.txt 文件安装包 deactivate # 退出虚拟环境 - 
方便在云端或新机器上快速部署项目环境。
 - 
检查包版本示例:
import pandas as pd print(pd.__version__) 
import 语句的工作原理 (How Import Works)
- 
从
math模块导入sqrt函数并重命名为s:from math import sqrt as s # 从 math 模块导入 sqrt 函数并重命名为 s import math as math_builtin # 导入 math 模块并重命名为 math_builtin result = math_builtin.pi * s(9) # 使用导入的模块和函数 print(result) - 
my_module.py(自定义模块文件):def welcome(): print("欢迎!") module_variable = "模块变量" - 
main.py(主程序文件):from my_module import welcome # 从 my_module 模块导入 welcome 函数 welcome() # 调用 my_module 模块中的 welcome 函数 - 
import语句用于将模块 (module) 中的代码加载到当前脚本中,允许使用模块中定义的函数、类和变量。 - 
导入
math模块的所有内容:from math import * # 导入 math 模块的所有内容 (不推荐,可能导致命名空间污染) - 
重命名导入的模块:
import math as m # 将 math 模块重命名为 m - 
列出模块的方法和属性:
import math print(dir(math)) # 使用 dir() 函数查看模块的属性和方法列表 
if __name__ == "__main__": 语句 (if name == "main")
if __name__ == "__main__":是 Python 脚本中常见的模式,用于判断脚本是被直接运行还是作为模块被导入到其他脚本中。
def main():
   print("脚本正在直接运行")
if __name__ == "__main__": # 当脚本被直接运行时,__name__ 的值为 "__main__"
   main() # 直接运行时执行 main() 函数
- 这种模式允许代码既可以作为脚本直接运行,也可以作为模块被导入到其他脚本中使用,而不会在导入时执行脚本中的代码。
 - 有助于组织代码,区分可以直接运行的代码和作为模块导入的代码。
 
好的,我们继续深入 Python 编程的学习之旅。
OS 模块 (OS Module)
import os
if not os.path.exists("data"): # 检查 "data" 目录是否存在
    os.mkdir("data") # 如果不存在,则创建 "data" 目录
for i in range(0, 100):
    os.makedirs(f"data/Day{i+1}", exist_ok=True) # 创建 "data/Day1", "data/Day2", ... "data/Day100" 等目录,exist_ok=True 表示目录已存在时不会报错
os模块是 Python 内置的操作系统接口模块,提供了许多与操作系统交互的函数。- 可以进行文件和目录操作,执行系统命令等。
 
try:
    f = os.open("file.txt", os.O_RDONLY) # 以只读模式打开文件 "file.txt"
    g = os.open("gfile.txt", os.O_WRONLY | os.O_CREAT) # 以只写模式打开文件 "gfile.txt",如果文件不存在则创建
    contents = os.read(f, 1024) # 从文件描述符 f 读取最多 1024 字节的内容
    os.write(g, b"你好,世界!") # 向文件描述符 g 写入字节字符串
    os.close(f) # 关闭文件描述符 f
    os.close(g) # 关闭文件描述符 g
except FileNotFoundError:
    print("文件未找到")
except Exception as e:
    print(f"发生错误: {e}")
- 
os.listdir(path)-> 获取指定目录path下的文件和目录列表。files = os.listdir(".") # 获取当前目录下的文件和目录列表 print(files) - 
os.mkdir(path)-> 创建一个目录path。 - 
os.makedirs(path, exist_ok=False)-> 递归创建目录path,可以创建多级目录。exist_ok=True表示如果目录已存在,不会抛出异常。 - 
运行系统命令:
os.system("date") # 在终端中执行 "date" 命令 (显示当前日期和时间) 
局部变量与全局变量 (Local & Global Variable)
x = 10 # 全局变量 x
def my_function():
    global x # 声明在函数内部使用的是全局变量 x
    x = 5  # 修改全局变量 x 的值
    y = 5  # 局部变量 y,只在函数内部有效
my_function()
print(x)  # 输出: 5 (全局变量 x 的值被函数修改)
# print(y)  # 报错: NameError: name 'y' is not defined (局部变量 y 在函数外部不可访问)
注意: 尽量避免在函数内部直接修改全局变量,容易导致代码维护性降低。
文件输入/输出 (File I/O)
try:
    f = open('myfile.txt', 'r', encoding='utf-8')  # 'r' -> 读取模式,encoding='utf-8' 指定编码
    print(f) # 打印文件对象信息
    text = f.read() # 读取文件所有内容
    print(text) # 打印文件内容
except FileNotFoundError:
    print("文件未找到")
finally:
    if 'f' in locals() and f and not f.closed: # 检查文件对象 f 是否已成功打开并存在
        f.close() # 确保文件被关闭
文件写入 (Writing to a File)
try:
    f = open('myfile.txt', 'a', encoding='utf-8') # 'a' -> 追加模式,encoding='utf-8' 指定编码
    f.write('你好,世界!\n') # 写入字符串到文件末尾,\n 表示换行
except Exception as e:
    print(f"写入文件时发生错误: {e}")
finally:
    if 'f' in locals() and f and not f.closed:
        f.close()
# 使用 with 语句,自动管理文件关闭
with open('myfile.txt', 'a', encoding='utf-8') as f:
    f.write("这是使用 with 语句写入的内容。\n") # 文件操作结束后,文件会自动关闭
文件模式 (Modes):
- 读取 (r):  打开文件用于读取,如果文件不存在则抛出 
FileNotFoundError异常。 - 写入 (w): 打开文件用于写入,如果文件不存在则创建新文件;如果文件已存在,则清空文件内容。
 - 追加 (a): 打开文件用于追加写入,如果文件不存在则创建新文件;如果文件已存在,则在文件末尾追加内容。
 - 创建 (x):  创建新文件,如果文件已存在则抛出 
FileExistsError异常。 - 文本模式 (t): 默认模式,处理文本文件,例如读取和写入字符串。
 - 二进制模式 (b): 用于处理二进制文件,例如图片、PDF 等。
 
注意: 使用
with open(...) as f:语句可以确保文件在使用完毕后自动关闭,即使发生异常也能保证文件资源被释放。
Lambda 函数 (Lambda Functions)
def apply_func(func, value):  # func 参数接收一个函数
    return 6 + func(value)
double = lambda x: x * 2 # 定义 lambda 函数 double,返回输入 x 的两倍
cube = lambda x: x ** 3 # 定义 lambda 函数 cube,返回输入 x 的立方
average = lambda x, y, z: (x + y + z) / 3 # 定义 lambda 函数 average,计算三个数的平均值
print(double(5))  # 输出: 10
print(apply_func(lambda x: x ** 2, 2))  # 输出: 10 (将 lambda 函数 x**2 作为参数传递给 apply_func)
- Lambda 函数 (匿名函数) 是一种简洁的函数定义方式,适用于简单的、功能单一的函数。
 - 语法: 
lambda arguments: expression(lambda 关键字,参数列表,冒号,返回值表达式) 
示例:
def multiply(x, y):
    return x * y
# Lambda 函数等价形式
lambda x, y: x * y
lambda x, y: print(f"{x} * {y} = {x * y}") # Lambda 函数也可以包含 print 等语句
Map, Filter, Reduce
- Map, Filter, Reduce 是 Python 中常用的高阶函数 (Higher-order functions),它们接收函数作为参数,并对序列 (或其他可迭代对象) 进行操作。
 
Map
map(function, iterable): 将函数function应用于可迭代对象iterable的每个元素,返回一个新的迭代器,包含每次函数调用的结果。
numbers = [1, 2, 3, 4, 5]
doubled_numbers = map(lambda x: x * 2, numbers) # 使用 map 函数和 lambda 函数将 numbers 列表中的每个元素乘以 2
print(list(doubled_numbers))  # 输出: [2, 4, 6, 8, 10] (将迭代器转换为列表输出)
Filter
filter(function, iterable): 使用函数function(返回布尔值) 过滤可迭代对象iterable的元素,返回一个新的迭代器,包含function返回True的元素。
numbers = [1, 2, 3, 4, 5]
even_numbers = filter(lambda x: x % 2 == 0, numbers) # 使用 filter 函数和 lambda 函数筛选 numbers 列表中的偶数
print(list(even_numbers))  # 输出: [2, 4] (将迭代器转换为列表输出)
Reduce
reduce(function, iterable[, initializer]): 将函数function(接收两个参数) 累积地应用于可迭代对象iterable的元素,将序列缩减为单个返回值。需要从functools模块导入。
from functools import reduce
numbers = [1, 2, 3, 4, 5]
sum_numbers = reduce(lambda x, y: x + y, numbers) # 使用 reduce 函数和 lambda 函数计算 numbers 列表中所有元素的和
print(sum_numbers)  # 输出: 15
is vs ==
a = None
b = None
print(a is b)  # True:  a 和 b 都指向 None 对象,是同一个对象 (身份相同)
print(a is None)  # True: a 是否是 None 对象 (身份比较)
print(a == b)  # True: a 和 b 的值相等 (值比较)
is和==都是 Python 中的比较运算符,但它们比较的内容不同。is: 比较的是 身份 (identity),即判断两个变量是否引用同一个对象 (内存地址是否相同)。==: 比较的是 值 (value),即判断两个变量的值是否相等。
示例:
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)  # True: a 和 b 的值相等 (元素相同,顺序相同)
print(a is b)  # False: a 和 b 是不同的列表对象,它们在内存中位于不同的位置 (身份不同)
注意: 对于不可变对象 (如字符串、小整数),Python 可能会进行对象缓存或 intern 机制,导致值相同的不同变量可能指向同一个对象,此时
is和==的结果可能相同,但一般情况下,应该使用==进行值比较,使用is比较对象身份,例如判断变量是否为None。
面向对象编程 (OOPS)
OOP 的四大支柱 (4 Pillars of OOP)
- 继承 (Inheritance): 属性共享,子类继承父类的属性和方法。
 - 封装 (Encapsulation): 数据隐藏,将数据和操作数据的方法封装在对象内部,对外隐藏实现细节。
 - 抽象 (Abstraction): 简化接口,只对外暴露必要的接口,隐藏复杂的内部实现。
 - 多态 (Polymorphism): 多种形态,允许不同类的对象对同一消息做出不同的响应。
 
### 面向对象编程 (Object-Oriented Programming)
- 类 (Class):  定义对象的蓝图或模板,描述对象的属性和行为。
- 属性 (Properties): 对象的数据或状态 (成员变量)。
 - 方法 (Methods): 对象可以执行的操作 (成员函数)。
 
 - 对象 (Object): 类的实例,包含类定义的属性和方法。每个对象都有自己的数据和方法。
 
## 封装 (Encapsulation)
- 封装 (Encapsulation) 的目的是隐藏对象的内部状态,并通过对象的方法来访问和修改状态。
 - 保护对象的数据,防止外部代码意外修改对象的状态。
 
访问修饰符 (Access Specifiers)
Python 中通过命名约定来实现访问控制,没有像 Java 或 C++ 那样的强制访问修饰符。
- 公共成员 (Public Members): 默认情况下,类的所有成员都是公共的,可以在类外部访问。
 - 受保护成员 (Protected Members):  以下划线 
_开头的成员,表示受保护的,建议在类内部和子类中使用,但不强制限制外部访问。 - 私有成员 (Private Members):  以双下划线 
__开头的成员,Python 会进行名称修饰 (name mangling),使其更难从外部直接访问,但并非完全无法访问。 
抽象 (Abstraction)
抽象 (Abstraction) 的目的是隐藏功能的内部实现细节,只对外暴露必要的接口。用户只需要知道如何使用接口,而不需要了解接口内部的复杂实现。
多态 (Polymorphism)
- 多态 (Polymorphism) 允许不同类的对象对同一消息 (方法调用) 做出不同的响应。
 - 提高代码的灵活性和可扩展性。
 
class Animal:
    def speak(self):
        pass # 父类 Animal 的 speak 方法默认不做任何事情
class Dog(Animal):
    def speak(self):
        return "汪汪!" # 子类 Dog 重写 speak 方法,返回 "汪汪!"
class Cat(Animal):
    def speak(self):
        return "喵喵!" # 子类 Cat 重写 speak 方法,返回 "喵喵!"
class Bird(Animal):
    def speak(self):
        return "啾啾!" # 子类 Bird 重写 speak 方法,返回 "啾啾!"
# 演示多态性的函数
def make_animal_speak(animal):
    print(animal.speak()) # 调用传入对象的 speak 方法,根据对象类型的不同,执行不同的 speak 方法
# 创建不同动物类的实例
dog = Dog()
cat = Cat()
bird = Bird()
# 演示多态性
make_animal_speak(dog)  # 输出: 汪汪! (调用 Dog 类的 speak 方法)
make_animal_speak(cat)  # 输出: 喵喵! (调用 Cat 类的 speak 方法)
make_animal_speak(bird) # 输出: 啾啾! (调用 Bird 类的 speak 方法)
类 (Classes)
类 (Class) 是创建对象的蓝图或模板,定义了对象的属性 (数据) 和方法 (行为)。
class Details:
    name = "张三" # 类属性 name
    age = 20 # 类属性 age
对象:类的实例 (Object: Instance of Class)
obj1 = Details() # 创建 Details 类的对象 obj1
print(obj1.name)  # 输出: 张三 (访问对象 obj1 的 name 属性)
print(obj1.age)  # 输出: 20 (访问对象 obj1 的 age 属性)
self 参数 (Self Parameter)
self参数在类的方法定义中是必需的,它指向类的当前实例 (对象) 本身。- 通过 
self可以访问对象的属性和调用对象的方法。 
class Details:
    name = "张三"
    age = 20
    def describe_person(self): # 类方法 describe_person,self 参数指向类的实例
        print("我的名字是", self.name, ",今年", self.age, "岁。") # 通过 self 访问对象的 name 和 age 属性
obj1 = Details() # 创建 Details 类的对象 obj1
obj1.describe_person() # 调用对象 obj1 的 describe_person 方法
示例 (Example)
class Person:
    name = "默认姓名" # 类属性 name
    occupation = "程序员" # 类属性 occupation
    net_worth = 10 # 类属性 net_worth
    def info(self): # 类方法 info
        print(f"{self.name} 是一名 {self.occupation}") # 使用 f-字符串格式化输出
a = Person() # 创建 Person 类的对象 a
b = Person() # 创建 Person 类的对象 b
c = Person() # 创建 Person 类的对象 c
a.name = "李四" # 修改对象 a 的 name 属性
a.occupation = "会计" # 修改对象 a 的 occupation 属性
b.name = "王五" # 修改对象 b 的 name 属性
b.occupation = "人力资源" # 修改对象 b 的 occupation 属性
a.info()  # 输出: 李四 是一名 会计 (调用对象 a 的 info 方法)
b.info()  # 输出: 王五 是一名 人力资源 (调用对象 b 的 info 方法)
c.info()  # 输出: 默认姓名 是一名 程序员 (调用对象 c 的 info 方法,使用默认属性值)
构造函数 (__init__)
- 构造函数 (
__init__方法) 是类中的特殊方法,用于创建和初始化类的对象。 - 当创建类的对象时,构造函数会自动被调用。
 - 主要作用是为对象的属性赋初始值。
 
def __init__(self):
    # __init__ -> Python 中的保留函数名,用于定义构造函数
    pass # pass 语句表示空代码块,什么也不做
- 
参数化构造函数 (Parameterized Constructors):
- 构造函数接收除了 
self之外的其他参数。 - 这些参数用于在创建对象时为对象的属性赋值。
 
class Details: def __init__(self, animal_name, animal_group): # 构造函数接收 animal_name 和 animal_group 参数 self.animal = animal_name # 将 animal_name 赋值给对象的 animal 属性 self.group = animal_group # 将 animal_group 赋值给对象的 group 属性 obj1 = Details("狮子", "食肉动物") # 创建 Details 类的对象 obj1,并传入参数 "狮子" 和 "食肉动物" print(obj1.animal, "属于", obj1.group) # 输出: 狮子 属于 食肉动物 (访问对象 obj1 的 animal 和 group 属性) - 构造函数接收除了 
 - 
默认构造函数 (Default Constructors):
- 构造函数只接收 
self参数,不接收其他参数。 - 如果类中没有显式定义构造函数,Python 会自动提供一个默认的构造函数 (不执行任何操作)。
 
class Details: def __init__(self): # 默认构造函数,只接收 self 参数 print("动物:狮子,食肉动物") obj1 = Details() # 创建 Details 类的对象 obj1,调用默认构造函数 # 输出: 动物:狮子,食肉动物 (构造函数中的 print 语句被执行) - 构造函数只接收 
 
装饰器 (Decorators)
- 
Python 装饰器 (Decorators) 是一种强大的工具,用于修改函数或方法的行为,而无需修改其源代码。
 - 
装饰器本质上是一个函数,它接收一个函数作为参数,并返回一个新的函数,新函数通常会在原函数的基础上增加一些功能。
 - 
新返回的函数被称为“被装饰”的函数。
@decorator_function # 使用 @ 符号应用装饰器 decorator_function 到 my_function 函数 def my_function(): passdef smart_divide(func): # 装饰器函数 smart_divide,接收一个函数 func 作为参数 def inner(a, b): # 内部函数 inner,接收参数 a 和 b print("我要计算", a, "除以", b) # 打印提示信息 if b == 0: print("不能除以零") # 如果除数为 0,打印错误信息 return # 提前返回,不执行原函数 return func(a, b) # 调用原函数 func 并返回结果 return inner # 返回内部函数 inner @smart_divide # 使用 @smart_divide 装饰 divide 函数 def divide(a, b): # 被装饰的函数 divide print(a / b) # 执行除法运算并打印结果 divide(2, 5) # 调用被装饰的 divide 函数 # 输出: # 我要计算 2 除以 5 # 0.4 divide(2, 0) # 调用被装饰的 divide 函数,除数为 0 # 输出: # 我要计算 2 除以 0 # 不能除以零 
Getter 方法 (Getters)
- Getter 方法 (取值器) 用于访问对象属性的值。
 - 通常使用 
@property装饰器定义,用于返回特定属性的值。 
   class MyClass:
       def __init__(self, value):
           self._value = value # 使用 _value 存储实际的值,以区分 getter 方法名
       @property # 使用 @property 装饰器将 value 方法定义为属性 getter
       def value(self): # 定义 getter 方法 value,方法名即属性名
           return self._value # 返回 _value 的值
   obj = MyClass(10) # 创建 MyClass 类的对象 obj,初始化 _value 为 10
   print(obj.value)  # 输出: 10 (访问 value 属性,实际调用 getter 方法)
注意: Getter 方法不接收参数,并且不能通过 getter 方法直接设置属性的值。
Setter 方法 (Setters)
    class MyClass:
        def __init__(self, value):
            self._value = value
        @property
        def value(self): # getter 方法
            return self._value
        @value.setter # 使用 @value.setter 装饰器定义 value 属性的 setter 方法
        def value(self, new_val): # setter 方法名必须与 getter 方法名相同
            if new_val < 0:
                raise ValueError("值不能为负数") # 添加数据验证逻辑
            self._value = new_val # 设置 _value 的新值
    obj = MyClass(10) # 创建 MyClass 类的对象 obj,初始化 _value 为 10
    obj.value = 20 # 设置 value 属性的值,实际调用 setter 方法
    print(obj.value)  # 输出: 20 (访问 value 属性,实际调用 getter 方法)
    # obj.value = -5 # 会抛出 ValueError 异常,因为 setter 方法中添加了数据验证
注意: Setter 方法与 getter 方法配合使用,可以实现对属性的受控访问,用于数据封装和数据验证。Setter 方法通常用于在设置属性值之前进行一些验证或处理。
继承 (Inheritance)
- 继承 (Inheritance) 是面向对象编程的重要特性,允许一个类 (子类或派生类) 继承另一个类 (父类或基类) 的属性和方法。
 - 子类可以复用父类的代码,并在此基础上进行扩展或修改。
 - 提高了代码的重用性和可维护性。
 
继承的类型 (Types of Inheritance):
- 
单继承 (Single Inheritance)
 - 
多继承 (Multiple Inheritance)
 - 
多层继承 (Multilevel Inheritance)
 - 
层次继承 (Hierarchical Inheritance)
 - 
混合继承 (Hybrid Inheritance)
 
单继承 (Single Inheritance)
- 子类只继承一个父类的属性和方法。
 
class Parent: # 父类 Parent
    def func1(self):
        print("父类方法")
class Child(Parent): # 子类 Child 继承自 Parent 类
    def func2(self):
        print("子类方法")
obj = Child() # 创建 Child 类的对象 obj
obj.func1()  # 输出: 父类方法 (子类对象可以调用父类的方法)
obj.func2()  # 输出: 子类方法 (子类对象可以调用子类自身的方法)
多继承 (Multiple Inheritance)
- 子类继承多个父类的属性和方法。
 
class Mother: # 父类 Mother
    mother_name = ""
    def mother(self):
        print("母亲姓名:", self.mother_name)
class Father: # 父类 Father
    father_name = ""
    def father(self):
        print("父亲姓名:", self.father_name)
class Son(Mother, Father): # 子类 Son 多继承自 Mother 和 Father 类
    def parents(self):
        print("父亲姓名:", self.father_name)
        print("母亲姓名:", self.mother_name)
s1 = Son() # 创建 Son 类的对象 s1
s1.father_name = "老爸" # 设置父类 Father 的属性
s1.mother_name = "老妈" # 设置父类 Mother 的属性
s1.parents() # 调用子类 Son 的 parents 方法
多层继承 (Multilevel Inheritance)
- 形成继承链,子类继承父类,父类又继承自更高级别的父类。
 
class Grandfather: # 祖父类
    def __init__(self, grandfather_name):
        self.grandfather_name = grandfather_name
class Father(Grandfather): # 父类 Father 继承自 Grandfather
    def __init__(self, father_name, grandfather_name):
        Grandfather.__init__(self, grandfather_name) # 调用父类 Grandfather 的构造函数
        self.father_name = father_name
class Son(Father): # 子类 Son 继承自 Father
    def __init__(self, father_name, grandfather_name, son_name):
        Father.__init__(self, father_name, grandfather_name) # 调用父类 Father 的构造函数
        self.son_name = son_name
    def print_name(self):
        print("祖父姓名:", self.grandfather_name)
        print("父亲姓名:", self.father_name)
        print("儿子姓名:", self.son_name)
s1 = Son("王子", "老王", "小王") # 创建 Son 类的对象 s1,并初始化各个父类的属性
s1.print_name() # 调用子类 Son 的 print_name 方法
层次继承 (Hierarchical Inheritance)
- 多个子类继承自同一个父类。
 
class Parent: # 父类 Parent
    def func1(self):
        print("父类方法")
class Child1(Parent): # 子类 Child1 继承自 Parent
    def func2(self):
        print("子类 Child1 方法")
class Child2(Parent): # 子类 Child2 继承自 Parent
    def func3(self):
        print("子类 Child2 方法")
obj1 = Child1() # 创建 Child1 类的对象 obj1
obj2 = Child2() # 创建 Child2 类的对象 obj2
obj1.func1() # 输出: 父类方法 (Child1 对象可以调用父类方法)
obj2.func1() # 输出: 父类方法 (Child2 对象可以调用父类方法)
obj1.func2() # 输出: 子类 Child1 方法 (Child1 对象可以调用自身方法)
obj2.func3() # 输出: 子类 Child2 方法 (Child2 对象可以调用自身方法)
混合继承 (Hybrid Inheritance)
- 混合使用多种继承类型,例如多层继承和多继承的组合。
 
class School: # 基类 School
    def func1(self):
        print("学校")
class Student1(School): # 子类 Student1 继承自 School
    def func2(self):
        print("学生 1")
class Student2(School): # 子类 Student2 继承自 School
    def func3(self):
        print("学生 2")
class Student3(Student1, School): # 子类 Student3 多继承自 Student1 和 School (注意继承顺序)
    def func4(self):
        print("学生 3 的方法")
obj1 = Student3() # 创建 Student3 类的对象 obj1
obj1.func1() # 输出: 学校 (Student3 对象可以调用 School 类的方法)
obj1.func2() # 输出: 学生 1 (Student3 对象可以调用 Student1 类的方法)
# obj1.func3() # Student3 类没有直接继承 Student2,无法调用 func3
obj1.func4() # 输出: 学生 3 的方法 (Student3 对象可以调用自身方法)
访问修饰符或访问控制 (Access Modifiers or Specifiers)
- 访问修饰符 (Access Modifiers) 用于控制类成员 (属性和方法) 的访问权限,限制从类外部访问类成员。
 - Python 中主要通过命名约定实现访问控制。
 
类型 (Types):
- 公共访问修饰符 (Public Access Modifiers)
 - 私有访问修饰符 (Private Access Modifiers)
 - 受保护访问修饰符 (Protected Access Modifiers)
 
class Student:
    def __init__(self):
        self._name = "小明"  # 受保护访问修饰符,以下划线开头
    def _fun_name(self):  # 受保护方法,以下划线开头
        return "张老师"
class Subject(Student): # 子类 Subject 继承自 Student
    pass
obj = Student() # 创建 Student 类的对象 obj
obj1 = Subject() # 创建 Subject 类的对象 obj1
print(dir(obj))  # 使用 dir() 函数查看对象 obj 的属性和方法列表,可以看到 _funName, __init__, _name 等
# 通过 Student 类的对象访问受保护成员
print(obj._name) # 访问受保护属性 _name
print(obj._fun_name()) # 调用受保护方法 _fun_name()
# 通过 Subject 类的对象访问受保护成员 (子类可以访问父类的受保护成员)
print(obj1._name) # 访问继承自父类的受保护属性 _name
print(obj1._fun_name()) # 调用继承自父类的受保护方法 _fun_name()
- 
公共访问修饰符 (Public Access Modifier): 默认情况下,类的所有成员都是公共的,可以在类外部自由访问。
self.age = age->age属性是公共的。
 - 
私有访问修饰符 (Private Access Modifier): 以双下划线
__开头的成员被视为私有成员,只能在类内部访问。- Python 中并没有严格的私有访问控制,以 
__开头的成员会被名称修饰 (name mangling),使其更难从外部直接访问,但仍然可以通过特殊方式访问。 
 - Python 中并没有严格的私有访问控制,以 
 
class Student:
    def __init__(self, age, name):
        self.__age = age  # 私有变量,以双下划线开头
    def __fun_name(self):  # 私有方法,以双下划线开头
        self.y = 34
        print(self.y)
class Subject(Student): # 子类 Subject 继承自 Student
    pass
obj = Student(21, "小明") # 创建 Student 类的对象 obj
obj1 = Subject() # 创建 Subject 类的对象 obj1
# 以下代码会抛出 AttributeError 错误,因为无法直接从外部访问私有成员
# print(obj.__age) # AttributeError: 'Student' object has no attribute '__age'
# obj.__fun_name() # AttributeError: 'Student' object has no attribute '__fun_name'
# print(obj1.__age) # AttributeError: 'Subject' object has no attribute '__age'
# obj1.__fun_name() # AttributeError: 'Subject' object has no attribute '__fun_name'
# 通过名称修饰后的名称访问私有变量 (不推荐,破坏了封装性)
print(obj._Student__age) # 可以通过 _ClassName__member_name 的方式访问私有成员
如何访问私有变量?:
*obj._Student__name*(例如,obj._Student__age),但不推荐这样做,应该尽量避免直接访问私有成员,而是通过公共方法 (如 getter 和 setter) 来间接访问。
方法重写 (Method Overriding)
class Shape: # 父类 Shape
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def area(self): # 父类方法 area,计算矩形面积
        return self.x * self.y
class Circle(Shape): # 子类 Circle 继承自 Shape
    def __init__(self, r):
        self.r = r
        super().__init__(r, r) # 调用父类 Shape 的构造函数,初始化 x 和 y 为 r
    def area(self): # 子类 Circle 重写父类 area 方法,计算圆形面积
        return 3.14 * super().area() # 调用父类 Shape 的 area 方法 (计算 r*r),再乘以 3.14
rect = Shape(3, 5) # 创建 Shape 类的对象 rect
print(rect.area()) # 输出矩形面积: 15 (调用父类 Shape 的 area 方法)
# 输出: 15
c = Circle(5) # 创建 Circle 类的对象 c
print(c.area())  # 输出圆形面积: 78.5 (调用子类 Circle 重写的 area 方法)
# 输出: 78.5
- 方法重写 (Method Overriding) 发生在继承关系中,子类可以重写 (override) 父类中已有的方法,提供自己的实现。
 - 当创建子类的对象并调用被重写的方法时,实际执行的是子类中重写后的版本,而不是父类中的版本。
 
静态方法 (Static Methods)
静态方法 (Static Methods) 是属于类本身的方法,而不是类的实例 (对象)。
- 使用 
@staticmethod装饰器定义。 - 静态方法 不能访问 类的实例 (对象) 属性 (即不能使用 
self参数)。 - 静态方法通常用于创建与类相关,但不依赖于特定实例的实用工具函数。
 
class Math:
   @staticmethod # 使用 @staticmethod 装饰器定义静态方法
   def add(a, b): # 静态方法 add,不接收 self 参数
      return a + b
result = Math.add(1, 2) # 直接通过类名 Math 调用静态方法 add
print(result)  # 输出: 3
类变量 vs 实例变量 (Class vs Instance Variables)
- 
类变量 (Class variables): 属于类本身的变量,被类的所有实例 (对象) 共享。
- 示例: 用于存储所有实例共享的通用信息。
 
 - 
实例变量 (Instance variables): 属于类的每个实例 (对象) 的变量,每个实例拥有独立的实例变量副本。
- 示例: 用于存储每个实例的特定信息。
 
 
访问变量 (Accessing Variables):
- 类变量:  
ClassName.variable或self.__class__.variable(在实例方法中) - 实例变量:  
self.variable_name(在实例方法中) 
class Animal:
   species = "哺乳动物"  # 类变量 species,所有 Animal 类的实例共享
   def __init__(self, name):
      self.name = name  # 实例变量 name,每个 Animal 类的实例拥有独立的 name 属性
a1 = Animal("狗") # 创建 Animal 类的对象 a1
a2 = Animal("猫") # 创建 Animal 类的对象 a2
print(a1.species)  # 输出: 哺乳动物 (访问对象 a1 的类变量 species)
print(a2.name)     # 输出: 猫 (访问对象 a2 的实例变量 name)
Animal.species = "动物" # 修改类变量 Animal.species
print(a1.species) # 输出: 动物 (类变量被修改后,所有实例访问到的类变量都改变了)
print(a2.species) # 输出: 动物
练习:清理文件夹内的杂乱文件 (重命名 PNG 文件) (Exercise: Clear Clutter Inside Folder)
重命名指定文件夹下所有 PNG 图片文件,按照序号顺序命名 (例如,1.png, 2.png 等)。
import os
folder_path = "clutter_folder" # 指定要清理的文件夹路径
files = os.listdir(folder_path) # 获取文件夹下所有文件和目录列表
i = 1 # 初始化序号计数器
for file in files:
    if file.endswith(".png"): # 检查文件名是否以 ".png" 结尾
        old_filepath = os.path.join(folder_path, file) # 构建旧文件完整路径
        new_filepath = os.path.join(folder_path, f"{i}.png") # 构建新文件完整路径
        os.rename(old_filepath, new_filepath) # 重命名文件
        i += 1 # 序号递增
print("PNG 文件重命名完成!")
练习:图书馆类 (Library Class Exercise)
创建一个 Library 类,包含两个实例变量:no_of_books (图书数量) 和 books (图书列表)。实现添加图书和打印图书信息的功能。
class Library:
   def __init__(self):
      self.no_of_books = 0 # 初始化图书数量为 0
      self.books = [] # 初始化图书列表为空列表
   def add_book(self, book_title): # 添加图书方法
      self.books.append(book_title) # 将图书标题添加到图书列表
      self.no_of_books = len(self.books) # 更新图书数量
   def show_info(self): # 显示图书馆信息方法
      print(f"图书馆藏书数量: {self.no_of_books}") # 打印图书数量
      if self.books: # 如果图书列表不为空
          print("馆藏图书列表:")
          for book in self.books: # 遍历图书列表
              print(f"- {book}") # 打印每本图书标题
      else:
          print("图书馆暂无藏书。")
l1 = Library() # 创建 Library 类的对象 l1
l1.add_book("哈利·波特") # 添加图书
l1.add_book("霍比特人") # 添加图书
l1.show_info() # 显示图书馆信息
# 输出:
# 图书馆藏书数量: 2
# 馆藏图书列表:
# - 哈利·波特
# - 霍比特人
Python 类方法 (Python Class Methods)
- 类方法 (Class methods) 是绑定到类本身而不是类的实例 (对象) 的方法。
 - 类方法操作的是类本身,而不是特定的实例。
 - 使用 
@classmethod装饰器定义。 - 常用于创建工厂方法或作为备用构造函数。
 
class Employee:
   company = "苹果公司" # 类变量 company
   def show(self): # 实例方法 show
      print(f"姓名: {self.name}, 公司: {self.company}")
   @classmethod # 使用 @classmethod 装饰器定义类方法
   def change_company(cls, new_company): # 类方法 change_company,cls 参数指向类本身
      cls.company = new_company # 修改类变量 company
e1 = Employee() # 创建 Employee 类的对象 e1
e1.name = "小明" # 设置实例属性 name
e1.show()  # 输出: 姓名: 小明, 公司: 苹果公司 (调用实例方法 show)
Employee.change_company("特斯拉") # 通过类名 Employee 调用类方法 change_company,修改类变量 company
e1.show()  # 输出: 姓名: 小明, 公司: 特斯拉 (再次调用实例方法 show,类变量 company 已被修改)
类方法作为备用构造函数 (Class Methods as Alternative Constructors)
class Employee:
   def __init__(self, name, salary): # 构造函数
      self.name = name
      self.salary = salary
   @classmethod # 使用 @classmethod 装饰器定义类方法
   def from_string(cls, employee_string): # 类方法 from_string,cls 参数指向类本身
      name, salary = employee_string.split("-") # 从字符串中解析姓名和工资
      return cls(name, int(salary)) # 使用 cls 调用类自身的构造函数,创建并返回类的新对象
e1 = Employee("小明", 1200) # 使用构造函数创建 Employee 对象
print(e1.name)     # 输出: 小明
print(e1.salary)   # 输出: 1200
e2 = Employee.from_string("李四-1500") # 使用类方法 from_string 创建 Employee 对象
print(e2.name)     # 输出: 李四
print(e2.salary)   # 输出: 1500
常用方法:dir(), __dict__, 和 help() (Useful Methods: dir(), __dict__, and help())
dir(object): 返回对象object的属性和方法列表 (包括特殊方法)。object.__dict__: 返回对象object的属性字典 (仅包含实例属性)。help(object): 显示对象object的帮助文档。
class Person:
   def __init__(self, name, age):
      self.name = name
      self.age = age
p = Person("小明", 30) # 创建 Person 类的对象 p
print(p.__dict__)   # 输出: {'name': '小明', 'age': 30} (查看对象 p 的实例属性字典)
print(dir(p))       # 输出: ['__class__', '__delattr__', ..., 'age', 'name'] (查看对象 p 的所有属性和方法)
help(Person)       # 查看 Person 类的帮助文档 (docstring)
super() 关键字 (Super Keyword)
super()函数用于调用父类 (超类) 的方法。- 在类继承中,子类经常需要扩展父类的行为,
super()可以方便地调用父类的方法,并在其基础上添加新的逻辑。 
class Employee: # 父类 Employee
   def __init__(self, name, employee_id): # 父类构造函数
      self.name = name
      self.id = employee_id
class Programmer(Employee): # 子类 Programmer 继承自 Employee
   def __init__(self, name, employee_id, language): # 子类构造函数
      super().__init__(name, employee_id) # 调用父类 Employee 的构造函数,初始化 name 和 id
      self.language = language # 初始化子类 Programmer 的属性 language
harry = Programmer("哈利", 23, "Python") # 创建 Programmer 类的对象 harry
print(harry.name)  # 输出: 哈利 (访问继承自父类的属性 name)
print(harry.language)  # 输出: Python (访问子类自身的属性 language)
Dunder (魔法) 方法 (Dunder (Magic) Methods)
- Dunder 方法 (Double Under Methods,也称为魔法方法或特殊方法) 是 Python 中以双下划线 
__开头和结尾的特殊方法。 - Dunder 方法用于自定义类的行为,例如运算符重载、对象字符串表示、长度计算等。
 
__init__(self, ...): 构造函数,在创建类的新实例时被调用 (初始化对象)。__str__(self)&__repr__(self): 将对象转换为字符串表示,__str__用于str()函数和print()函数,__repr__用于repr()函数和交互式环境输出。__len__(self): 返回对象的长度,用于len()函数。__call__(self, ...): 使对象可以像函数一样被调用。
class Employee:
   def __init__(self, name): # 构造函数
      self.name = name
   def __len__(self): # 定义 __len__ 方法,返回姓名长度
      return len(self.name)
   def __str__(self): # 定义 __str__ 方法,返回对象的友好的字符串表示
      return f"员工: {self.name}"
   def __repr__(self): # 定义 __repr__ 方法,返回对象的明确的字符串表示 (通常用于调试和开发)
      return f"Employee('{self.name}')"
   def __call__(self): # 定义 __call__ 方法,使对象可以像函数一样被调用
      print(f"你好,我是 {self.name}")
e = Employee("小明") # 创建 Employee 类的对象 e
print(len(e))      # 输出: 2 (调用 __len__ 方法,返回姓名长度)
print(str(e))      # 输出: 员工: 小明 (调用 __str__ 方法,返回友好的字符串表示)
print(repr(e))     # 输出: Employee('小明') (调用 __repr__ 方法,返回明确的字符串表示)
e()                # 输出: 你好,我是 小明 (将对象 e 作为函数调用,执行 __call__ 方法)
方法重写 (Method Overriding) (再次强调)
- 方法重写 (Method Overriding) 允许子类重新定义父类的方法,以实现不同的行为。
 - 当调用子类对象的重写方法时,会执行子类中定义的版本。
 
class Shape: # 父类 Shape
   def __init__(self, x, y):
      self.x = x
      self.y = y
   def area(self): # 父类方法 area,计算矩形面积
      return self.x * self.y
class Circle(Shape): # 子类 Circle 继承自 Shape
   def __init__(self, r):
      super().__init__(r, r) # 调用父类 Shape 的构造函数
   def area(self): # 子类 Circle 重写父类 area 方法,计算圆形面积
      return 3.14 * super().area() # 调用父类 Shape 的 area 方法 (计算 r*r),再乘以 3.14
rect = Shape(3, 5) # 创建 Shape 类的对象 rect
print(rect.area())  # 输出: 15 (调用父类 Shape 的 area 方法)
circle = Circle(5) # 创建 Circle 类的对象 circle
print(circle.area())  # 输出: 78.5 (调用子类 Circle 重写的 area 方法)
运算符重载 (Operator Overriding)
- 运算符重载 (Operator Overriding) 允许你自定义运算符 (如 
+,-,*,==等) 对于自定义类对象的操作行为。 - 通过实现 dunder 方法 (如 
__add__,__sub__,__mul__,__eq__等) 来重载运算符。 
class Vector:
   def __init__(self, i, j, k):
      self.i = i
      self.j = j
      self.k = k
   def __add__(self, other): # 重载 + 运算符,定义向量加法
      return Vector(self.i + other.i, self.j + other.j, self.k + other.k) # 返回新的 Vector 对象,表示向量和
   def __str__(self): # 重载 str() 函数,定义向量的字符串表示
      return f"{self.i}i + {self.j}j + {self.k}k"
v1 = Vector(3, 5, 6) # 创建 Vector 对象 v1
v2 = Vector(1, 2, 9) # 创建 Vector 对象 v2
v3 = v1 + v2 # 使用 + 运算符进行向量加法,实际调用 __add__ 方法
print(v3)  # 输出: 4i + 7j + 15k (打印向量 v3 的字符串表示,实际调用 __str__ 方法)
注意:
super()关键字在继承中非常有用,可以扩展父类方法的行为,而不是完全替换它。在子类方法中,先使用super()调用父类的方法,然后再添加子类特有的逻辑,是一种良好的编程实践。
练习:合并 PDF 文件为一个 PDF 文件 (Exercise: Merge PDFs into a Single PDF)
from PyPDF2 import PdfMerger # 导入 PdfMerger 类
import os
merger = PdfMerger() # 创建 PdfMerger 对象
pdf_files = [file for file in os.listdir() if file.endswith(".pdf")] # 获取当前目录下所有 PDF 文件列表
for pdf in pdf_files: # 遍历 PDF 文件列表
    merger.append(pdf) # 将每个 PDF 文件添加到 PdfMerger 对象中
merger.write("Merged-pdf.pdf") # 将合并后的 PDF 内容写入到 "Merged-pdf.pdf" 文件
merger.close() # 关闭 PdfMerger 对象
print("PDF 文件合并完成!")
输出:
- 将当前目录下所有 PDF 文件合并为一个名为 
Merged-pdf.pdf的 PDF 文件。 
Time 模块 (Time Module):
- 
time模块提供了一组函数,用于处理时间相关的操作,如时间获取、时间格式化、时间转换等。 - 
常用函数 (Common Functions):
- 
time.time(): 返回当前时间的时间戳 (timestamp),即从 Epoch (1970 年 1 月 1 日 00:00:00 UTC) 到现在的秒数。示例 (Example):
import time start_time = time.time() # 获取当前时间戳 print("当前时间戳:", start_time) - 
time.sleep(seconds): 使程序暂停执行指定的秒数seconds。示例 (Example):
import time print("开始") time.sleep(2) # 程序暂停 2 秒 print("2 秒后结束") - 
time.strftime(format[, t]): 根据指定的格式format将时间元组t(可选,默认为当前时间) 格式化为字符串。示例 (Example):
import time t = time.localtime() # 获取当前时间的本地时间元组 formatted_time = time.strftime("%Y-%m-%d, %H:%M:%S", t) # 格式化时间为 "年-月-日, 时:分:秒" 字符串 print(formatted_time) 
 - 
 
命令行实用工具 (Command Line Utility):
- 命令行程序 (Command-line programs) 对于自动化任务和提高开发工作效率至关重要。
 
基本示例 (Basic Example):
import argparse # 导入 argparse 模块
parser = argparse.ArgumentParser(description="这是一个示例命令行程序") # 创建 ArgumentParser 对象,并设置程序描述信息
parser.add_argument("arg1", help="第一个参数的描述") # 添加位置参数 arg1,并设置帮助信息
parser.add_argument("arg2", help="第二个参数的描述") # 添加位置参数 arg2,并设置帮助信息
args = parser.parse_args() # 解析命令行参数
print("参数 1:", args.arg1) # 访问解析后的参数 arg1
print("参数 2:", args.arg2) # 访问解析后的参数 arg2
文件下载器示例 (File Downloader Example):
import argparse
import requests
import shutil
def download_file(url, local_filename=None):
    if local_filename is None:
        local_filename = url.split('/')[-1] # 如果未指定本地文件名,则从 URL 中提取文件名
    try:
        response = requests.get(url, stream=True) # 发送 GET 请求,stream=True 表示使用流式下载
        response.raise_for_status() # 检查请求状态码,如果不是 200 OK 则抛出异常
        with open(local_filename, 'wb') as out_file: # 以二进制写入模式打开本地文件
            shutil.copyfileobj(response.raw, out_file) # 使用 shutil.copyfileobj 高效复制流数据到文件
        print(f"文件下载成功: {local_filename}")
    except requests.exceptions.RequestException as e: # 捕获 requests 模块的异常
        print(f"文件下载失败: {e}")
    finally:
        if 'response' in locals() and response:
            response.close() # 确保 response 连接被关闭
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="从 URL 下载文件") # 创建 ArgumentParser 对象
    parser.add_argument("url", help="文件 URL") # 添加位置参数 url,帮助信息为 "文件 URL"
    parser.add_argument("output", help="输出文件名") # 添加位置参数 output,帮助信息为 "输出文件名"
    args = parser.parse_args() # 解析命令行参数
    download_file(args.url, args.output) # 调用 download_file 函数下载文件
    # print("文件已下载:", args.output) # 打印下载完成信息,download_file 函数内部已打印成功信息
输出:
- 从提供的 URL 下载文件,并保存为指定的输出文件名。
 
海象运算符 (:=):
- 海象运算符 (Walrus Operator) 
:=是在 Python 3.8 中引入的新特性,允许在表达式内部进行赋值。 
示例 (Example):
happy = False
print("之前:", happy)
print("之后:", happy := True) # 使用海象运算符 := 在 print 函数内部将 happy 赋值为 True 并打印赋值结果
foods = list()
while (food := input("你喜欢什么食物?(输入 'quit' 退出): ")) != "quit": # 使用海象运算符 := 将 input() 的返回值赋值给 food 变量,并在 while 条件中判断
    foods.append(food)
print("你喜欢的食物列表:", foods)
shutil 模块 (shutil Module):
shutil模块是 Python 中用于高级文件操作的实用工具模块。
常用函数 (Functions):
shutil.copy(src, dst): 复制文件src到dst(目标可以是文件或目录)。shutil.copy2(src, dst): 复制文件src到dst,并保留元数据 (如时间戳)。shutil.copytree(src, dst): 递归复制整个目录树src到dst。shutil.move(src, dst): 移动文件或目录src到dst。shutil.rmtree(path): 递归删除目录树path(慎用!)。
Beautiful Soup (bs4): Web Scraping (网页抓取)
- Beautiful Soup 是一个 Python 库,用于从 HTML 和 XML 文件中提取数据,常用于网页抓取 (Web Scraping)。
 
import requests
from bs4 import BeautifulSoup
url = "https://www.example.com" # 目标网页 URL
try:
    r = requests.get(url) # 发送 GET 请求获取网页内容
    r.raise_for_status() # 检查请求状态码
    soup = BeautifulSoup(r.text, "html.parser") # 使用 BeautifulSoup 解析 HTML 内容,html.parser 是 HTML 解析器
    print("格式化后的 HTML:\n", soup.prettify()) # 打印格式化后的 HTML 代码 (美化输出)
    headings = soup.find_all("h1") # 查找所有 <h1> 标签
    if headings:
        print("\n网页标题 (h1 标签):")
        for heading in headings: # 遍历找到的 <h1> 标签
            print(heading.text.strip()) # 打印 <h1> 标签的文本内容,并去除首尾空白
    else:
        print("\n网页中没有 h1 标题。")
except requests.exceptions.RequestException as e:
    print(f"请求网页失败: {e}")
except Exception as e:
    print(f"解析网页内容失败: {e}")
输出:
- 打印整个网页内容的结构化格式 (美化后的 HTML 代码) 和所有 
<h1>标题的文本内容。 
生成器 (Generators):
- 生成器 (Generators) 是一种特殊的函数,允许你逐个迭代生成值,而无需一次性将所有值都存储在内存中。
 - 生成器使用 
yield关键字产生值,而不是return。 
示例 (Example):
def my_generator(n): # 定义生成器函数 my_generator
    for i in range(n):
        yield i # 使用 yield 关键字产生值 i
gen = my_generator(5) # 创建生成器对象 gen
print(next(gen))  # 输出: 0 (使用 next() 函数获取生成器的下一个值)
print(next(gen))  # 输出: 1
print(next(gen))  # 输出: 2
for j in gen: # 使用 for 循环迭代生成器,从上次 yield 的位置继续执行
    print(j)  # 输出: 3, 4 (for 循环会自动处理 StopIteration 异常,当生成器没有更多值时循环结束)
函数缓存 (@lru_cache):
- 函数缓存 (Function Caching) 使用缓存 (Cache) 存储函数的计算结果,避免对相同输入重复计算,适用于计算开销较大的函数。
 - Python 中可以使用 
functools.lru_cache装饰器实现函数缓存。 
示例 (Example):
from functools import lru_cache # 导入 lru_cache 装饰器
import time
@lru_cache(maxsize=None) # 使用 @lru_cache 装饰器,maxsize=None 表示缓存大小无限制
def fx(n): # 定义函数 fx,模拟耗时计算
    time.sleep(2)  # 模拟耗时操作,休眠 2 秒
    return n * 5
start_time = time.time()
print(fx(20))  # 第一次调用 fx(20),需要计算 2 秒
print(f"第一次调用 fx(20) 耗时: {time.time() - start_time:.2f} 秒")
start_time = time.time()
print(fx(2))   # 第一次调用 fx(2),需要计算 2 秒
print(f"第一次调用 fx(2) 耗时: {time.time() - start_time:.2f} 秒")
start_time = time.time()
print(fx(6))   # 第一次调用 fx(6),需要计算 2 秒
print(f"第一次调用 fx(6) 耗时: {time.time() - start_time:.2f} 秒")
# 下面的调用将直接从缓存中读取结果,无需重新计算,几乎是瞬间完成
start_time = time.time()
print(fx(20)) # 第二次调用 fx(20),从缓存中读取结果,无需计算
print(f"第二次调用 fx(20) 耗时: {time.time() - start_time:.2f} 秒")
start_time = time.time()
print(fx(2))  # 第二次调用 fx(2),从缓存中读取结果,无需计算
print(f"第二次调用 fx(2) 耗时: {time.time() - start_time:.2f} 秒")
start_time = time.time()
print(fx(6))  # 第二次调用 fx(6),从缓存中读取结果,无需计算
print(f"第二次调用 fx(6) 耗时: {time.time() - start_time:.2f} 秒")
正则表达式 (Regex):
- 正则表达式 (Regular Expressions 或 Regex) 是一种强大的文本模式匹配工具,用于在字符串中查找、替换、验证特定模式的文本。
 - Python 中使用 
re模块处理正则表达式。 
基本正则表达式 (Basic Regex):
import re
pattern = r"表达式"  # raw 字符串,定义正则表达式模式 (例如 r"hello")
text = "你好,世界!" # 要搜索的文本
match = re.search(pattern, text) # 使用 re.search() 函数在 text 中搜索 pattern 模式,返回 Match 对象或 None
if match:
    print("找到匹配项!") # 如果找到匹配项
else:
    print("未找到匹配项。") # 如果未找到匹配项
示例 (Example):
import re
text = "The cat is in the hat and a bat." # 文本字符串
pattern = r"[a-z]+at" # 正则表达式模式:匹配一个或多个小写字母 (a-z),后跟 "at"
matches = re.findall(pattern, text) # 使用 re.findall() 函数查找文本中所有匹配模式的子字符串,返回列表
print("匹配项:", matches)  # 输出: ['cat', 'hat', 'bat']
new_text = re.sub(pattern, "dog", text) # 使用 re.sub() 函数将文本中所有匹配 pattern 的子字符串替换为 "dog",返回替换后的新字符串
print("替换后的文本:", new_text)  # 输出: "The dog is in the dog and a dog."
提取邮箱地址 (Extracting Emails):
import re
text = "我的邮箱是 example@example.com,另一个邮箱是 test.user@domain.net。" # 包含邮箱地址的文本
pattern = r"\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\b" # 匹配邮箱地址的正则表达式模式 (更精确的邮箱格式匹配)
matches = re.findall(pattern, text) # 查找所有匹配邮箱地址的子字符串
if matches:
    print("提取到的邮箱地址:")
    for email in matches: # 遍历找到的邮箱地址
        print(f"- {email}") # 打印每个邮箱地址
else:
    print("未找到邮箱地址。")
AsyncIO (异步 I/O)
asyncio模块提供了异步 I/O 编程的支持,允许程序在等待 I/O 操作 (如网络请求、文件读写) 完成时,继续执行其他任务,提高程序的并发性和效率。
import asyncio
import requests
async def download_image(url, filename): # 定义异步函数 download_image,使用 async 关键字
    print(f"开始下载: {filename}")
    response = requests.get(url) # 发送同步 HTTP 请求 (requests 库是同步的)
    if response.status_code == 200:
        with open(filename, "wb") as f:
            f.write(response.content)
        print(f"下载完成: {filename}")
    else:
        print(f"下载失败: {filename}, 状态码: {response.status_code}")
    return filename # 返回文件名
async def main(): # 定义主异步函数 main
    image_urls = [
        ("https://www.easygifanimator.net/images/samples/video-to-gif-sample.gif", "image1.gif"),
        ("https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_November_2010-1a.jpg", "image2.jpg"),
        ("https://www.thoughtco.com/thmb/zQDr3lG080p4Z_MA8dtmSjhqQ94=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/close-up-of-cat-eyes-873370984-5c7ff4b4c929250001f6b383.jpg", "image3.jpg"),
    ]
    tasks = [] # 创建任务列表
    for url, filename in image_urls:
        task = asyncio.create_task(download_image(url, filename)) # 使用 asyncio.create_task 创建异步任务
        tasks.append(task)
    downloaded_files = await asyncio.gather(*tasks) # 使用 asyncio.gather 并发执行所有任务,并等待所有任务完成,获取返回值列表
    print("下载完成的文件:", downloaded_files)
if __name__ == "__main__":
    asyncio.run(main()) # 使用 asyncio.run 运行主异步函数 main
输出:
- image1.gif, image2.jpg, 和 image3.jpg 将被下载到本地目录。
 - 打印下载完成的文件名列表。
 
多线程 (MultiThreading)
- 多线程 (MultiThreading) 允许在一个进程中创建多个线程,并发执行代码,提高程序的并发性。
 - Python 中使用 
threading模块实现多线程。 - 创建线程 -> 调用线程对象的 
start()方法启动线程。 join()方法用于等待线程执行结束。
import threading
def my_func(): # 线程执行的函数
    print(f"你好,来自线程 {threading.current_thread().name}") # 打印当前线程的名字
thread = threading.Thread(target=my_func) # 创建新的线程,target 参数指定线程执行的函数
thread.start() # 启动线程
thread.join() # 等待线程执行结束
print("主线程继续执行")
输出:
你好,来自线程 Thread-1(线程名字可能略有不同,取决于系统分配)主线程继续执行
常用函数 (Functions):
- 
threading.Thread(target, args):- 创建一个新的线程,
target参数指定线程要执行的函数,args参数以元组形式传递给target函数的参数。 
 - 创建一个新的线程,
 - 
threading.Lock():- 创建一个锁 (Lock) 对象,用于同步多线程对共享资源的访问,防止数据竞争。
 - 锁确保在同一时刻只有一个线程可以访问临界区 (critical section) 代码。
 
 
使用锁的示例 (Example with Lock):
import threading
def increment(counter, lock): # 线程执行的函数,counter 是共享计数器,lock 是锁对象
    for _ in range(100000): # 循环增加计数器
        lock.acquire() # 获取锁,进入临界区
        counter[0] += 1 # 增加共享计数器
        lock.release() # 释放锁,退出临界区
if __name__ == "__main__":
    counter = [0]  # 使用列表存储计数器,因为列表是可变对象,可以在线程间共享和修改
    lock = threading.Lock() # 创建锁对象
    threads = [] # 存储线程对象的列表
    for _ in range(2): # 创建两个线程
        thread = threading.Thread(target=increment, args=(counter, lock)) # 创建线程,指定执行函数和参数
        threads.append(thread) # 添加线程到列表
        thread.start() # 启动线程
    for thread in threads: # 等待所有线程执行结束
        thread.join()
    print(f"最终计数器值: {counter[0]}") # 打印最终计数器值,期望值为 200000 (两个线程各增加 100000)
输出:
- 最终计数器值将会是 
200000(理论上,实际运行结果可能因系统调度等因素略有偏差,但使用锁可以很大程度上避免数据竞争)。 
使用 ThreadPoolExecutor (Using ThreadPoolExecutor)
import time
from concurrent.futures import ThreadPoolExecutor # 导入 ThreadPoolExecutor 类
def func(seconds): # 模拟耗时操作的函数
    print(f"线程 {threading.current_thread().name} 休眠 {seconds} 秒")
    time.sleep(seconds)
    return seconds
def main():
    time1 = time.perf_counter() # 记录开始时间
    # 使用线程池
    with ThreadPoolExecutor(max_workers=3) as executor: # 创建线程池,最大工作线程数为 3
        futures = []
        for i in range(3):
            seconds_to_sleep = 4 - i # 休眠时间递减
            future = executor.submit(func, seconds_to_sleep) # 提交任务到线程池,返回 Future 对象
            futures.append(future)
        results = [future.result() for future in futures] # 获取所有 Future 对象的结果,会阻塞等待任务完成
        print("任务结果:", results)
    time2 = time.perf_counter() # 记录结束时间
    print(f"程序总耗时: {time2 - time1:.2f} 秒") # 打印程序总耗时
if __name__ == "__main__":
    main()
输出:
- 线程会并发执行 
func函数,总耗时会远小于串行执行的时间,大约在 4 秒左右 (取决于最长的休眠时间)。 - 输出线程休眠信息和程序总耗时。
 
多进程 (Multiprocessing)
multiprocessing模块提供了创建和管理进程的功能,允许程序利用多核 CPU 并行执行任务,充分利用系统资源,提高计算密集型任务的性能。
import concurrent.futures
import requests
import os
import time
def download_image(url, name): # 下载图片的函数
    start_time = time.time()
    try:
        print(f"进程 {os.getpid()} 开始下载 {name}") # 打印进程 ID 和下载文件名
        response = requests.get(url, stream=True) # 发送 HTTP 请求,stream=True 使用流式下载
        response.raise_for_status() # 检查请求状态码
        file_path = f"{name}.jpg"
        with open(file_path, "wb") as file:
            for chunk in response.iter_content(chunk_size=8192): # 分块写入文件
                file.write(chunk)
        end_time = time.time()
        print(f"进程 {os.getpid()} 完成下载 {name},耗时: {end_time - start_time:.2f} 秒")
        return f"{name}.jpg" # 返回保存的文件名
    except requests.exceptions.RequestException as e:
        print(f"进程 {os.getpid()} 下载 {name} 失败: {e}")
        return None
if __name__ == "__main__":
    image_url = "https://picsum.photos/200/300" # 图片 URL
    image_names = [f"image_{i}" for i in range(50)] # 生成 50 个图片文件名
    start_time = time.time()
    with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor: # 创建进程池,最大工作进程数为 4
        processes = []
        for name in image_names:
            process = executor.submit(download_image, image_url, name) # 提交下载任务到进程池
            processes.append(process)
        downloaded_files = [process.result() for process in concurrent.futures.as_completed(processes)] # 获取已完成进程的结果
        downloaded_files = [file for file in downloaded_files if file] # 过滤掉下载失败的文件
    end_time = time.time()
    print(f"所有图片下载完成,总耗时: {end_time - start_time:.2f} 秒")
    print(f"成功下载的文件数量: {len(downloaded_files)}")
输出:
- 脚本会并发下载 50 张图片,使用多进程可以显著缩短下载时间,尤其在 CPU 密集型任务或 I/O 密集型任务中,多进程可以充分利用多核 CPU 的性能。
 - 输出每个进程的下载开始、完成信息以及总耗时和成功下载的文件数量。
 
多进程 vs 多线程 (Multiprocessing vs Multithreading)
序号	多进程	                     多线程
1.	    添加 CPU 以提高计算能力。	     创建单个进程的多个线程以实现并发。
2.	    同时执行多个进程。	         同时执行进程的多个线程。
3.	    分为对称和非对称多进程。	     不分为类别。
4.	    进程创建耗时较长。	         线程创建更经济。
5.	    每个进程都拥有单独的地址空间。	 所有线程共享一个公共地址空间。
本文在@ARYANK-08的python fundamentals的基础上修改和完善。