第六阶段:进阶基础,筑牢编程底层能力
😄生命不息,写作不止
🔥 继续踏上学习之路,学之分享笔记
👊 总有一天我也能像各位大佬一样
🏆 博客首页 @怒放吧德德 To记录领地 @一个有梦有戏的人
🌝分享学习心得,欢迎指正,大家一起学习成长!
🔥豆包AI
转发请携带作者信息 @怒放吧德德(掘金) @一个有梦有戏的人(CSDN)
前言
在第五阶段,我们吃透了函数基础的核心知识点——从函数的定义与调用,到参数、返回值、局部与全局变量,再到匿名函数、函数嵌套与递归,我们终于摆脱了“零散代码”的困境,实现了代码的复用与模块化。
而第六阶段我们要攻克的「进阶基础」,是Python编程从“会用”走向“活用”的关键一步,更是后续学习复杂项目、框架(如Django、PyTorch)的核心基石。这一阶段,我们将重点学习四大核心内容:模块与包(实现代码的规模化复用)、文件操作(实现数据的持久化存储)、异常处理(让代码更健壮、容错性更强)、面向对象基础(解锁更灵活的编程思维)。
本阶段的学习难度相较于前五个阶段略有提升,核心目标不再是“记住语法”,而是“理解逻辑、灵活运用”。全程将延续“知识点解析+可运行代码+避坑技巧”的模式,贴合新手学习节奏,每个代码示例都可直接复制运行,每个知识点都搭配通俗解读,跟着敲代码、练案例,就能轻松掌握进阶基础的核心能力,稳步向“合格的Python初学者”迈进~
1 模块与包:实现代码规模化复用,告别“复制粘贴”
在第五阶段,我们用函数实现了“代码片段的复用”,但当项目越来越大、函数越来越多,我们会发现:大量函数堆砌在一个文件中,不仅难以查找、维护,还容易出现命名冲突。而「模块与包」,就是为解决这个问题而生的——它们能帮我们将代码按功能分类、组织,实现“跨文件复用”,让代码结构更清晰、更具可扩展性。
简单来说:模块(Module) 是一个包含Python代码的 .py 文件(比如my_module.py),里面可以定义函数、类、变量;包(Package) 是一个包含多个模块(.py文件)的目录,目录下必须有一个 __init__.py 文件(可为空),用于标识这个目录是一个Python包。
1.1 模块的使用:import导入(核心操作)
Python提供了多种导入模块的方式,核心是使用 import 关键字,新手重点掌握4种常用方式,结合示例理解,可直接复制运行。
# 方式1:导入整个模块(最基础)
# 语法:import 模块名
import random # 导入Python内置的随机数模块(无需自己创建)
# 使用模块中的函数/变量:模块名.函数名() / 模块名.变量名
print("随机整数(1-10):", random.randint(1, 10))
print("随机浮点数(0-1):", random.random())
# 方式2:导入模块并指定别名(简化调用,常用)
# 语法:import 模块名 as 别名
import datetime as dt # 导入内置日期时间模块,别名dt
# 使用别名调用,更简洁
now = dt.datetime.now()
print("当前时间:", now.strftime("%Y-%m-%d %H:%M:%S"))
# 方式3:从模块中导入指定的函数/变量(推荐,按需导入)
# 语法:from 模块名 import 函数名1, 函数名2, 变量名
from math import pi, sqrt # 从内置数学模块导入pi(圆周率)和sqrt(开平方)
print("圆周率pi:", pi)
print("9的平方根:", sqrt(9)) # 输出3.0
# 方式4:从模块中导入所有内容(不推荐,易出现命名冲突)
# 语法:from 模块名 import *
from random import *
print("随机选择列表元素:", choice([1, 2, 3, 4, 5]))
# 注意:这种方式会导入模块中所有可导入的内容,若与自身定义的函数/变量同名,会覆盖
1.2 自定义模块:自己写模块,实现跨文件复用
除了使用Python内置模块,我们还可以自己编写模块(.py文件),将自己定义的函数、类、变量放入其中,供其他文件导入使用——这是实际编程中常用的技巧,实现代码的跨文件复用。
步骤:① 创建一个 .py 文件(模块文件),编写代码(函数、类等);② 在另一个文件中,用import导入这个模块,即可使用其中的内容。
# 第一步:创建自定义模块(文件名:my_module.py,与当前运行文件放在同一目录下)
# ------------------ my_module.py 内容 ------------------
# 定义一个计算两数之和的函数
def add(a, b):
return a + b
# 定义一个计算两数之差的函数
def subtract(a, b):
return a - b
# 定义一个全局变量
PI = 3.1415926
# 模块自测:当模块被直接运行时,执行以下代码(导入时不执行)
# 控制模块执行(入口点)
if __name__ == "__main__":
print("模块自测:3+5 =", add(3, 5))
print("模块自测:10-4 =", subtract(10, 4))
# ------------------------------------------------------
# 第二步:在当前文件(比如main.py)中导入自定义模块,使用其中的内容
# 导入自定义模块
import my_module
# 使用模块中的函数
print("3+5 =", my_module.add(3, 5)) # 输出8
print("10-4 =", my_module.subtract(10, 4)) # 输出6
# 使用模块中的变量
print("圆周率(自定义模块):", my_module.PI) # 输出3.1415926
# 也可以用别名导入
import my_module as mm
print("5+8 =", mm.add(5, 8)) # 输出13
# 也可以按需导入
from my_module import add, PI
print("2+7 =", add(2, 7)) # 输出9
关键知识点:if __name__ == "__main__": —— 每个模块都有一个 __name__ 属性,当模块被直接运行时,__name__ 的值为 "__main__",此时会执行该判断下的代码(用于模块自测);当模块被导入时,__name__ 的值为模块名,该判断下的代码不会执行。
类似 Java 的 main 方法
public class MyClass {
public static void main(String[] args) { // 入口点 }}
1.3 包的使用:组织多个模块,实现功能分类
当自定义模块越来越多(比如10个、20个),我们可以用“包”将它们按功能分类(比如数据处理相关的模块放在一个包,工具类模块放在另一个包)。包的核心是“目录+init.py文件”。
示例(包的创建与导入):
# 第一步:创建包(目录结构如下)
# my_package/ # 包目录
# __init__.py # 必须有,可为空文件(标识该目录是Python包)
# calc_module.py # 模块1:计算相关函数
# tool_module.py # 模块2:工具相关函数
# 第二步:编写包内模块的代码
# ------------------ calc_module.py 内容 ------------------
def multiply(a, b):
return a * b
def divide(a, b):
return a / b if b != 0 else "除数不能为0"
# ------------------------------------------------------
# ------------------ tool_module.py 内容 ------------------
def print_info(info):
print(f"【信息】:{info}")
def is_positive(num):
return num > 0
# ------------------------------------------------------
# 第三步:导入包中的模块,使用其中的内容
# 方式1:导入包中的某个模块
from my_package import calc_module, tool_module
print("3×5 =", calc_module.multiply(3, 5)) # 输出15
tool_module.print_info("Python包的使用示例") # 输出【信息】:Python包的使用示例
# 方式2:导入包中模块的指定函数
from my_package.calc_module import multiply
from my_package.tool_module import is_positive
print("4×6 =", multiply(4, 6)) # 输出24
print("5是否为正数:", is_positive(5)) # 输出True
# 方式3:给包/模块指定别名
from my_package import tool_module as tm
tm.print_info("别名导入示例") # 输出【信息】:别名导入示例
1.4 常用内置模块(新手必学,直接可用)
Python内置了大量实用模块,无需自己编写,导入即可使用,新手重点掌握以下5个,能解决80%的基础编程场景:
# 1. random:随机数模块(常用)
import random
print("随机整数(1-100):", random.randint(1, 100))
print("随机选择元素:", random.choice(["苹果", "香蕉", "橙子"]))
print("打乱列表:", random.shuffle([1, 2, 3, 4, 5])) # 原地打乱
# 2. datetime:日期时间模块(常用)
import datetime
now = datetime.datetime.now() # 获取当前时间
print("当前时间:", now)
print("格式化时间(年-月-日):", now.strftime("%Y-%m-%d"))
print("3天后的日期:", now + datetime.timedelta(days=3))
# 3. math:数学模块(常用)
import math
print("圆周率:", math.pi)
print("16的平方根:", math.sqrt(16)) # 4.0
print("绝对值:", math.fabs(-5.2)) # 5.2
print("正弦值(弧度):", math.sin(math.pi/2)) # 1.0
# 4. os:操作系统相关模块(文件路径、目录操作)
import os
print("当前目录路径:", os.getcwd()) # 获取当前工作目录
print("当前目录下的文件:", os.listdir()) # 列出当前目录下所有文件/目录
# os.mkdir("test_dir") # 创建一个名为test_dir的目录(需确保目录不存在)
# 5. sys:系统相关模块(简单了解)
import sys
print("Python版本:", sys.version) # 查看Python版本
print("命令行参数:", sys.argv) # 查看命令行参数
1.5 新手避坑指南(模块与包必看)
- 避坑1:自定义模块名、包名,不要与Python内置模块名重名(比如不要命名为random.py、math.py),否则会覆盖内置模块,导致报错;
- 避坑2:导入模块时,若模块不在当前目录下,会报错——解决方案:将模块所在目录添加到Python的搜索路径,或把模块放在当前运行文件同一目录;
- 避坑3:包目录下必须有
__init__.py文件(可为空),否则Python不会将其识别为包,无法导入; - 避坑4:尽量避免使用
from 模块名 import *,容易出现命名冲突,推荐按需导入(from 模块名 import 函数名); - 避坑5:
if __name__ == "__main__":仅用于模块自测,导入模块时不会执行,不要依赖它实现核心功能。
2 文件操作:实现数据持久化,让数据“存得住”
在前面的学习中,我们处理的数据(比如列表、字典、变量),都是“临时数据”——程序运行结束后,数据就会被销毁。而实际编程中,我们常常需要将数据“保存到文件中”(比如用户信息、日志、数据结果),也需要从文件中“读取数据”——这就是「文件操作」的核心作用:实现数据的持久化存储。
Python中文件操作的核心是 open() 函数,用于打开文件,然后通过相关方法实现读取、写入、关闭,重点掌握“打开→操作→关闭”的流程,以及更简洁、安全的 with 上下文管理器。
2.1 文件操作的核心流程:打开→读取/写入→关闭
文件操作必须遵循“打开文件→操作文件(读/写)→关闭文件”的流程——关闭文件是重中之重,若忘记关闭,会导致文件资源泄露、文件被占用(无法再次打开),甚至数据丢失。
# 核心语法:open(文件路径, 打开模式, encoding=编码格式)
# 1. 打开文件(以读取模式打开,encoding='utf-8'避免中文乱码)
# 注意:若文件不存在,r模式会报错
file = open("test.txt", "r", encoding="utf-8")
# 2. 读取文件内容(三种常用方式)
# 方式1:read():读取全部内容,返回字符串
content1 = file.read()
print("read()读取全部内容:", content1)
# 方式2:readline():读取一行内容,每次调用读取下一行
file.seek(0) # 重置文件指针到开头(否则会从上次读取的位置继续)
content2 = file.readline()
print("readline()读取第一行:", content2)
content3 = file.readline()
print("readline()读取第二行:", content3)
# 方式3:readlines():读取所有行,返回列表(每行为一个元素)
file.seek(0)
content4 = file.readlines()
print("readlines()读取所有行:", content4) # 输出:['第一行内容\n', '第二行内容\n', '第三行内容']
# 3. 关闭文件(必须执行,否则会导致资源泄露)
file.close()
# 补充:写入文件(w模式:覆盖写入,若文件不存在则创建)
file2 = open("test.txt", "w", encoding="utf-8")
file2.write("这是覆盖写入的内容\n") # 写入字符串
file2.write("这是第二行写入的内容")
file2.close() # 关闭文件后,写入内容才会生效
# 补充:追加写入(a模式:在文件末尾追加,不覆盖原有内容)
file3 = open("test.txt", "a", encoding="utf-8")
file3.write("\n这是追加的内容")
file3.close()
2.2 关键知识点:打开模式(必记)
open()函数的第二个参数“打开模式”,决定了文件操作的类型(读/写/追加),新手重点记以下6种常用模式:
# 常用打开模式(核心必记)
# 1. r:只读模式(默认),若文件不存在则报错,只能读取,不能写入
# 2. w:覆盖写入模式,若文件不存在则创建,若文件存在则覆盖原有内容
# 3. a:追加写入模式,若文件不存在则创建,写入内容追加到文件末尾
# 4. r+:读写模式,既能读取,也能写入(不会覆盖原有内容,从指针位置开始写入)
# 5. w+:读写模式,覆盖写入(若文件不存在则创建),既能写也能读
# 6. a+:读写模式,追加写入,既能写也能读
# 示例:r+模式(读写)
file = open("test.txt", "r+", encoding="utf-8")
content = file.read()
print("读取内容:", content)
file.write("\nr+模式写入的内容") # 在文件末尾写入(因为指针在读取后到了末尾)
file.close()
# 示例:w+模式(覆盖读写)
file = open("test2.txt", "w+", encoding="utf-8")
file.write("w+模式覆盖写入的内容")
file.seek(0) # 重置指针到开头,否则读取不到内容
content = file.read()
print("w+模式读取内容:", content)
file.close()
2.3 with上下文管理器:自动关闭文件,更简洁、更安全
新手最容易踩的坑:忘记关闭文件(file.close()),导致文件资源泄露。而 with 上下文管理器,能帮我们自动关闭文件——进入with代码块时,自动打开文件;退出with代码块时,自动关闭文件(无论代码是否报错),无需手动调用close(),是文件操作的“首选方式”。
# with上下文管理器(读取文件,推荐用法)
with open("test.txt", "r", encoding="utf-8") as file:
# 缩进内的代码的是文件操作范围,退出缩进后,文件自动关闭
content = file.read()
print("with读取文件:", content)
# 退出with后,文件已自动关闭,无需手动close()
# print(file.read()) # 报错:文件已关闭,无法读取
# with写入文件(覆盖写入)
with open("test3.txt", "w", encoding="utf-8") as file:
file.write("with模式写入的内容\n")
file.write("自动关闭文件,无需手动操作")
# with追加写入
with open("test3.txt", "a", encoding="utf-8") as file:
file.write("\n追加写入的内容")
# with同时打开多个文件(比如复制文件内容)
with open("test3.txt", "r", encoding="utf-8") as read_file, \
open("test4.txt", "w", encoding="utf-8") as write_file:
# 读取test3.txt的内容,写入test4.txt(实现文件复制)
content = read_file.read()
write_file.write(content)
print("文件复制完成!")
核心优势:用with操作文件,既简洁(少写close()),又安全(即使代码块中报错,也会自动关闭文件),新手全程优先使用这种方式。
2.4 文件路径:找到文件的“准确位置”
文件操作时,若文件不在当前运行目录下,直接写文件名会报错——此时需要指定“文件路径”,文件路径分为两种:相对路径和绝对路径。
# 1. 相对路径(常用):以当前运行文件的目录为基准,查找文件
# 示例1:文件在当前目录下(直接写文件名)
with open("test.txt", "r", encoding="utf-8") as file:
pass
# 示例2:文件在当前目录的子目录下(比如data目录下)
# 目录结构:当前文件 → data → test5.txt
with open("data/test5.txt", "r", encoding="utf-8") as file:
pass
# 示例3:文件在当前目录的上级目录下
# 目录结构:上级目录 → 当前文件目录 → 当前文件;上级目录 → test6.txt
with open("../test6.txt", "r", encoding="utf-8") as file:
pass # ../ 表示上级目录
# 2. 绝对路径(精准,不会出错):从电脑的根目录开始,指定完整路径
# Windows系统(注意路径中的反斜杠用\\,或用正斜杠/)
with open("D:\\Python\\test7.txt", "r", encoding="utf-8") as file:
pass
# 或
with open("D:/Python/test7.txt", "r", encoding="utf-8") as file:
pass
# Mac/Linux系统(路径用正斜杠/)
with open("/Users/xxx/Python/test7.txt", "r", encoding="utf-8") as file:
pass
# 补充:用os模块获取当前路径,避免路径错误(推荐)
import os
# 获取当前运行文件的目录路径
current_dir = os.path.dirname(os.path.abspath(__file__))
# 拼接文件路径(兼容Windows和Mac/Linux)
file_path = os.path.join(current_dir, "test.txt")
# 使用拼接后的路径打开文件
with open(file_path, "r", encoding="utf-8") as file:
content = file.read()
print("通过os模块拼接路径读取:", content)
2.5 新手避坑指南(文件操作必看)
- 避坑1:操作中文文件时,必须指定
encoding="utf-8",否则会出现中文乱码或报错; - 避坑2:忘记关闭文件——优先使用with上下文管理器,自动关闭文件,无需手动操作;
- 避坑3:w模式是“覆盖写入”,慎用!一旦使用w模式打开已有文件,原有内容会被全部清空,无法恢复;
- 避坑4:读取文件后,文件指针会移动到读取结束的位置,再次读取会读取不到内容,需用
file.seek(0)重置指针; - 避坑5:文件路径错误——若文件不在当前目录,需指定相对路径或绝对路径,推荐用os模块拼接路径,避免手动写路径出错;
- 避坑6:with代码块外,无法访问文件对象(文件已自动关闭),不要在with外操作文件。
3 异常处理:让代码更健壮,从容应对“报错”
在前面的学习中,我们写的代码一旦出现错误(比如文件不存在、除以零、输入错误),程序就会直接崩溃,抛出异常(报错信息)。而「异常处理」,就是通过特定的语法,捕获程序运行中的异常,处理异常(比如给出友好提示),让程序不会崩溃,继续执行——这是编写“健壮代码”的核心技能。
Python中异常处理的核心语法是try-except,配合 finally、raise,实现完整的异常处理逻辑。
3.1 基础异常处理:try-except(捕获异常)
语法逻辑:尝试执行try代码块中的代码,若出现异常,就执行except代码块中的代码(处理异常);若没有异常,就跳过except代码块,执行后续代码。
# 示例1:捕获所有异常(简单,但不推荐,无法定位具体异常类型)
try:
# 尝试执行的代码(可能会报错的代码)
num1 = int(input("请输入第一个数字:"))
num2 = int(input("请输入第二个数字:"))
result = num1 / num2
print(f"结果:{num1} ÷ {num2} = {result}")
except:
# 出现异常时,执行的代码(处理异常)
print("出错了!请输入正确的数字,且除数不能为0!")
# 示例2:捕获指定类型的异常(推荐,能精准处理不同异常)
try:
num1 = int(input("请输入第一个数字:"))
num2 = int(input("请输入第二个数字:"))
result = num1 / num2
print(f"结果:{num1} ÷ {num2} = {result}")
except ValueError:
# 捕获“值错误”(比如输入的不是数字)
print("出错了!请输入整数类型的数字!")
except ZeroDivisionError:
# 捕获“除以零错误”
print("出错了!除数不能为0,请重新输入!")
# 示例3:捕获多个指定异常,统一处理
try:
# 尝试打开文件读取
with open("test_not_exist.txt", "r", encoding="utf-8") as file:
content = file.read()
except (FileNotFoundError, UnicodeDecodeError):
# 捕获“文件不存在”或“编码错误”
print("出错了!文件不存在或编码格式错误!")
# 示例4:捕获异常,并获取异常信息(便于调试)
try:
num1 = int(input("请输入第一个数字:"))
num2 = int(input("请输入第二个数字:"))
result = num1 / num2
except ValueError as e:
# e 是异常对象,存储异常信息
print(f"值错误:{e}") # 输出具体的错误信息,比如:invalid literal for int() with base 10: 'abc'
except ZeroDivisionError as e:
print(f"除以零错误:{e}") # 输出:division by zero
3.2 finally语句:无论是否异常,都必须执行
finally 语句用于定义“无论是否出现异常,都必须执行的代码”,常用场景:资源清理(比如关闭文件、断开数据库连接)——即使try代码块报错,finally代码块也会执行。
# 示例1:finally基本用法
try:
num1 = int(input("请输入第一个数字:"))
num2 = int(input("请输入第二个数字:"))
result = num1 / num2
print(f"结果:{result}")
except ZeroDivisionError:
print("除数不能为0!")
finally:
# 无论是否异常,都会执行
print("程序执行完毕(无论成功还是失败)")
# 示例2:finally用于资源清理(即使报错,也会关闭文件)
file = None
try:
file = open("test.txt", "r", encoding="utf-8")
content = file.read()
print(content)
except FileNotFoundError:
print("文件不存在!")
finally:
# 无论是否异常,都关闭文件(避免资源泄露)
if file: # 判断文件是否成功打开
file.close()
print("文件已关闭")
# 补充:with上下文管理器已自动处理关闭文件,无需用finally,但其他资源清理可使用
try:
with open("test.txt", "r", encoding="utf-8") as file:
content = file.read()
except FileNotFoundError:
print("文件不存在!")
finally:
print("文件操作流程结束")
3.3 raise语句:主动抛出异常,控制程序逻辑
raise 语句用于“主动抛出异常”——当我们检测到不符合预期的条件时,主动让程序抛出异常,中断执行,或让上层代码处理异常。
# 示例1:主动抛出异常(基础用法)
def check_age(age):
# 检测年龄是否合法,不合法则主动抛出异常
if age < 0 or age > 120:
# 主动抛出ValueError异常,并指定异常信息
raise ValueError("年龄不合法!年龄必须在0-120之间")
print(f"年龄合法:{age}岁")
# 调用函数,捕获主动抛出的异常
try:
check_age(-5) # 不符合条件,主动抛出异常
except ValueError as e:
print(f"捕获异常:{e}") # 输出:捕获异常:年龄不合法!年龄必须在0-120之间
try:
check_age(25) # 合法,正常执行
except ValueError as e:
print(f"捕获异常:{e}")
# 示例2:结合函数,主动抛出异常,控制逻辑
def login(username, password):
# 模拟登录验证,若用户名或密码为空,主动抛出异常
if not username:
raise Exception("用户名不能为空!")
if not password:
raise Exception("密码不能为空!")
print("登录验证通过,正在进入系统...")
# 调用登录函数
try:
login("", "123456")
except Exception as e:
print(f"登录失败:{e}") # 输出:登录失败:用户名不能为空!
3.4 新手避坑指南(异常处理必看)
- 避坑1:不要滥用
except:捕获所有异常——无法定位具体的错误类型,不利于调试,推荐捕获指定类型的异常; - 避坑2:finally代码块中不要写return语句——会覆盖try/except中的return值,导致异常信息丢失;
- 避坑3:raise语句抛出的异常,必须有对应的except捕获,否则程序依然会崩溃;
- 避坑4:异常处理的核心是“处理异常”,不是“隐藏异常”——不要只捕获异常,不给出任何提示,否则会导致程序异常却无法排查;
- 避坑5:资源清理(如关闭文件),优先用with上下文管理器,若手动打开文件,需在finally中关闭,避免资源泄露。
4 面向对象基础:解锁更灵活的编程思维
在前面的学习中,我们用“面向过程”的思维编写代码——按步骤拆解问题,一步一步执行(比如先定义函数,再调用函数,按顺序执行逻辑)。而「面向对象」,是一种更灵活、更贴近现实世界的编程思维——将现实世界中的事物(比如人、汽车、学生)抽象成“类”,用类创建“对象”,通过对象的属性和方法实现功能。
面向对象的核心概念:类(Class) 和 对象(Object)。类是“模板”(比如“学生”类),对象是“模板的实例”(比如“张三”“李四”这两个具体的学生);类中包含“属性”(事物的特征,比如学生的姓名、年龄)和“方法”(事物的行为,比如学生的学习、吃饭)。
4.1 类与对象:核心概念与创建
Python中用 class 关键字定义类,类名通常采用“大驼峰命名法”(首字母大写,多个单词首字母均大写,比如Student、Person);通过“类名()”创建对象(实例化对象)。
# 示例1:定义一个简单的类(Student类)
class Student:
# 类的属性(学生的特征):可以直接定义,也可以通过初始化方法定义
# 类属性:所有对象共享的属性(比如学生的学校)
school = "北京大学"
# 类的方法(学生的行为):定义在类中的函数,第一个参数必须是self
def study(self):
# self 代表当前对象(调用该方法的对象),必须作为第一个参数
print(f"{self.name} 正在学习Python基础!")
def eat(self):
print(f"{self.name} 正在吃饭!")
# 示例2:创建对象(实例化对象)
# 创建第一个对象(张三)
stu1 = Student()
# 给对象添加实例属性(每个对象独有的属性,比如姓名、年龄)
stu1.name = "张三"
stu1.age = 18
# 调用对象的方法
stu1.study() # 输出:张三 正在学习Python基础!
stu1.eat() # 输出:张三 正在吃饭!
# 访问对象的属性(实例属性和类属性)
print(f"姓名:{stu1.name},年龄:{stu1.age},学校:{stu1.school}")
# 创建第二个对象(李四)
stu2 = Student()
stu2.name = "李四"
stu2.age = 19
stu2.study() # 输出:李四 正在学习Python基础!
print(f"姓名:{stu2.name},年龄:{stu2.age},学校:{stu2.school}")
# 访问类属性(通过类名访问,所有对象共享)
print("类属性(学校):", Student.school)
关键知识点:self —— 类中定义的方法,第一个参数必须是self,self代表“当前调用方法的对象”,通过self可以访问对象的属性和其他方法,调用方法时,无需手动传递self参数(Python会自动传递)。
4.2 __init__初始化方法:创建对象时自动初始化属性
前面的示例中,我们创建对象后,需要手动给对象添加实例属性(stu1.name = "张三"),非常繁琐。而 __init__ 方法(初始化方法),是类的特殊方法,创建对象时会自动调用,用于初始化对象的属性——相当于“对象的构造函数”,能帮我们简化对象的创建过程。
重点:__init__ 前后各有两个下划线(双下划线),是Python的特殊方法命名规范;第一个参数必须是self,后续参数用于接收创建对象时传递的属性值。
# 示例:定义带有__init__初始化方法的Student类(推荐用法)
class Student:
# 类属性(所有对象共享)
school = "北京大学"
# __init__初始化方法:创建对象时自动调用,初始化实例属性
# self:必须有,代表当前对象
# name、age:接收创建对象时传递的参数,作为实例属性
def __init__(self, name, age):
# 给当前对象添加实例属性,绑定参数值
self.name = name
self.age = age
# 可以在__init__中添加额外的初始化逻辑
print(f"创建学生对象:{self.name},{self.age}岁")
# 类中的方法
def study(self):
print(f"{self.name}({self.age}岁)正在学习Python第六阶段内容!")
def introduce(self):
# 访问实例属性和类属性
print(f"大家好,我是{self.name},今年{self.age}岁,来自{self.school}")
# 创建对象:创建时直接传递参数,__init__自动调用,初始化属性
stu1 = Student("张三", 18) # 输出:创建学生对象:张三,18岁
stu2 = Student("李四", 19) # 输出:创建学生对象:李四,19岁
# 直接访问对象的实例属性(无需手动添加)
print(f"stu1:{stu1.name},{stu1.age}岁")
print(f"stu2:{stu2.name},{stu2.age}岁")
# 调用对象的方法
stu1.study() # 输出:张三(18岁)正在学习Python第六阶段内容!
stu2.introduce() # 输出:大家好,我是李四,今年19岁,来自北京大学
# 补充:修改实例属性和类属性
stu1.age = 20 # 修改stu1的实例属性(仅影响stu1)
print(f"张三修改后的年龄:{stu1.age}岁")
Student.school = "清华大学" # 修改类属性(所有对象共享,都会影响)
print(f"stu1的学校:{stu1.school}")
print(f"stu2的学校:{stu2.school}")
关键提醒:__init__ 方法不是“构造函数”,Python中对象的创建由 __new__ 方法完成,__init__ 仅用于对创建好的对象进行初始化操作,新手无需深究 __new__ 方法,重点掌握__init__ 的用法即可。
构造方法,类似 Java:
public class MyClass {
public MyClass() { // 构造方法 // 初始化代码 }}
4.3 类的属性与方法:详细解析
类中包含两种核心元素:属性(特征)和方法(行为),按作用范围可分为“类属性/类方法”和“实例属性/实例方法”,新手重点掌握实例属性和实例方法。
# 示例:详细区分实例属性、类属性、实例方法
class Person:
# 1. 类属性:定义在类中,不在任何方法中,所有对象共享
species = "人类" # 所有Person对象的species属性都是“人类”
# 2. __init__初始化方法:初始化实例属性(每个对象独有)
def __init__(self, name, age):
# 实例属性:定义在__init__中,通过self绑定,每个对象独有
self.name = name
self.age = age
# 3. 实例方法:定义在类中,第一个参数是self,只能通过对象调用
def sleep(self):
print(f"{self.name}({self.age}岁)正在睡觉")
# 4. 类方法(简单了解):定义在类中,用@classmethod装饰,第一个参数是cls(代表类)
@classmethod
def show_species(cls):
print(f"物种:{cls.species}") # 通过cls访问类属性
# 访问类属性(两种方式)
print(Person.species) # 方式1:通过类名访问(推荐)
p1 = Person("张三", 18)
print(p1.species) # 方式2:通过对象访问(不推荐,类属性应通过类名访问)
# 访问实例属性(只能通过对象访问)
print(p1.name, p1.age)
# print(Person.name) # 报错:类不能访问实例属性
# 调用实例方法(只能通过对象访问)
p1.sleep()
# 调用类方法(两种方式)
Person.show_species() # 方式1:通过类名访问(推荐)
p1.show_species() # 方式2:通过对象访问
# 补充:修改属性
# 修改类属性(影响所有对象)
Person.species = "智人"
p2 = Person("李四", 19)
print(p1.species) # 输出:智人
print(p2.species) # 输出:智人
# 修改实例属性(仅影响当前对象)
p1.age = 20
print(p1.age) # 输出:20
print(p2.age) # 输出:19
4.4 新手避坑指南(面向对象基础必看)
- 避坑1:
__init__方法前后必须各有两个下划线,少写或多写都会变成普通方法,无法自动调用; - 避坑2:类中定义的方法,第一个参数必须是self(实例方法)或cls(类方法),否则调用时会报错;
- 避坑3:实例属性只能通过对象访问,类不能访问实例属性;类属性可以通过类名或对象访问,但推荐通过类名访问;
- 避坑4:修改类属性时,必须通过“类名.类属性”修改,通过“对象.类属性”修改,本质是给对象添加一个同名的实例属性,不会修改类属性;
- 避坑5:不要混淆“类”和“对象”——类是模板,不能直接使用方法/属性(除类方法、类属性),必须创建对象,通过对象使用实例方法和实例属性;
- 避坑6:
__init__方法不能有return语句(除非return None),否则会报错。
5 总结
恭喜大家!Python3基础学习第六阶段「进阶基础」的核心内容,到这里就全部梳理完毕了!这一阶段,我们跳出了“基础语法”的范畴,学习了四大核心进阶知识点,每一个都对后续的Python学习至关重要:
- 模块与包:帮我们组织代码、实现跨文件复用,告别代码堆砌和命名冲突,为编写大型项目打下基础;
- 文件操作:实现数据的持久化存储,让我们能读取、写入文件,处理实际场景中的数据(如用户信息、日志);
- 异常处理:让代码更健壮、容错性更强,从容应对程序运行中的错误,避免程序崩溃;
- 面向对象基础:解锁“面向对象”的编程思维,将现实世界的事物抽象成类和对象,让代码更灵活、更易维护。
第六阶段的学习,难度明显提升——不仅需要记住语法,更需要理解逻辑、转变思维(尤其是面向对象思维,从“面向过程”到“面向对象”的转变,新手可能需要一定时间适应)。对于新手来说,重点注意以下几点:
- 模块与包:重点掌握import导入的4种方式、自定义模块的编写与导入,以及常用内置模块的使用,多练习跨文件复用代码;
- 文件操作:全程优先使用with上下文管理器,牢记常用打开模式,掌握相对路径和绝对路径的API.
转发请携带作者信息 @怒放吧德德 @一个有梦有戏的人
持续创作很不容易,作者将以尽可能的详细把所学知识分享各位开发者,一起进步一起学习。转载请携带链接,转载到微信公众号请勿选择原创,谢谢!
👍创作不易,如有错误请指正,感谢观看!记得点赞哦!👍
谢谢支持!