Python——模块、异常、面向对象

一、模块(Module)

1.1 什么是模块

模块就是 .py 结尾的 Python 源代码文件,文件中可以存放变量、函数、类、可执行代码。 作用:

  1. 将庞大项目拆分成多个文件,代码解耦,提高可读性;

  2. 实现代码复用,一次编写,多处导入调用;

  3. 区分命名空间,不同模块内部同名变量互不干扰。

包(Package):多个功能相关模块放在同一个文件夹,文件夹包含__init__.py文件,就构成包,用来管理一组模块。

复制代码
外层大文件夹(项目根目录)
├── my_package/  【包:工具文件夹,只负责存工具代码】
│    ├── __init__.py   必须包含
│    ├── demo_module.py  模块一
│    └── tool.py  模块二
└── main.py       【主程序文件】

1.1.1 包内模块代码示例

文件1:my_package/demo_module.py

python 复制代码
author = "python学习"

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

class Student:
    def __init__(self,name):
        self.name = name

文件2:my_package/tool.py(新增工具模块)

python 复制代码
def sub(a,b):
    return a - b

def msg_show():
    print("包内工具模块执行成功")

1.1.3 在主文件导入「包里面的模块」

main.py 中使用包导入:

python 复制代码
# 语法:包名.模块名
from my_package.demo_module import add,Student
from my_package.tool import sub,msg_show

print(add(10,20))
print(sub(100,50))
s = Student("小红")
print(s.name)
msg_show()

1.2 模块的 4 种导入方式

python 复制代码
# 方式1:import 模块名,完整导入整个模块,访问必须加模块名.
import demo_module
print(demo_module.author)
print(demo_module.add(3,5))
s = demo_module.Student("小李")

# 方式2:from 模块名 import 变量/函数/类,只导入指定成员,直接使用名字
from demo_module import add,Student
print(add(10,20))
s2 = Student("小王")

# 方式3:导入起别名,简化书写,避免名字冲突
import demo_module as dm
print(dm.add(1,2))

from demo_module import add as my_add
print(my_add(4,6))

# 方式4:from 模块 import * 通配导入,导入模块全部公开成员
# from demo_module import *
# ❗不推荐:容易发生命名覆盖,不清楚哪些变量来自模块

1.3 if __name__ == "__main__"核心机制

每个模块自带内置变量__name__

  1. 直接运行这个 py 文件__name__自动等于字符串"__main__"

  2. 该文件被别的文件 import 导入__name__等于模块文件名。

python 复制代码
author = "python学习"

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

# 测试代码,只有直接运行本文件才执行,被导入不会执行
if __name__ == "__main__":
    print(add(100,200))
    print("当前作为脚本直接运行")

开发规范:模块的测试代码全部写在 if 判断内部,防止导入模块时自动执行测试逻辑。

1.4 模块搜索路径

当你写 import 模块名 时,Python 不知道你的文件在哪 ,它会按固定 3 个顺序 挨个文件夹找 ,找不到就直接报错。这 3 个用来找模块的文件夹列表,就叫 模块搜索路径

  1. import 导入模块,优先级从上到下:

  2. 第一步:先找当前文件夹(你正在运行代码的文件夹)

  3. 第二步:找系统 PYTHONPATH 路径(提前配置好的第三方库路径)

  4. 第三步:找 Python 自带库路径(math、random、sys 这些内置库)

python 复制代码
import sys
print(sys.path) # 打印全部搜索路径列表

1.5 注意

  1. 自定义文件名不要和内置模块重名,不要创建random.pymath.py,会覆盖系统模块,原生功能直接失效;

  2. 导入模块时,模块顶层的代码会自上而下完整执行一遍,不要把大量业务逻辑写在模块最外层;

  3. Python3.3 支持隐式命名空间包,但正式项目建议文件夹保留__init__.py

  4. 修改模块源码后,重复 import 不会重新加载,需要importlib.reload()手动重载;

  5. 不在sys.path里的文件夹,import 找不到模块,需要手动追加路径。

1.6 使用场景

  • 工具函数抽离为工具模块;

  • 大型项目按功能拆分多个模块、包;

  • 调用 Python 标准库:os、sys、random、json。


二、异常处理(Error & Exception)

2.1 什么是异常

程序运行阶段发生错误,Python 会抛出异常对象。 如果代码没有捕获异常,程序直接终止,后续代码全部不再运行。

异常处理目的:捕获运行时错误,给出友好提示,保证程序不会直接崩溃。

语法错误(SyntaxError)属于写代码语法写错,try‑except 无法捕获,解释器解析阶段就报错。

2.2 try‑except‑else‑finally 完整语法

python 复制代码
try:
    # 【监控区】可能抛出异常的业务代码
    num = int(input("请输入数字:"))
    res = 10 / num
except ValueError as ve:
    # 捕获:数值转换失败异常
    print(f"数值异常:{ve}")
except ZeroDivisionError as ze:
    # 捕获:除数为0异常
    print(f"除零异常:{ze}")
except Exception as e:
    # 兜底父类异常,捕获以上没有匹配到的所有异常
    print(f"其他未知异常:{e}")
else:
    # ✅只有try代码块**完全没有异常**的时候,才执行else
    print(f"计算结果={res}")
finally:
    # 🔔无论是否报错、return、break,finally一定执行!常用于资源释放
    print("执行finally,关闭资源")

执行逻辑:

  1. try 内部代码正常走完 → 执行 else → 执行 finally;

  2. try 抛出异常,匹配对应 except → 执行 except → 跳过 else →执行 finally。

2.3 raise 主动抛出异常

代码检测业务条件不满足,可以手动抛出异常,向上层调用者反馈错误。

python 复制代码
def check_age(age):
    # 判断是否为整数类型
    if not isinstance(age,int):
        raise TypeError("年龄必须是整数")
    # 判断数值范围是否合法
    if age < 0 or age >150:
        raise ValueError("年龄范围必须0‑150")
    print(f"合法年龄:{age}")

# ========== 以下为【3组测试用例】 ==========
# 测试用例1:合法年龄(无异常,正常执行)
print("-----测试用例1:合法年龄-----")
try:
    check_age(20)
except (TypeError, ValueError) as err:
    print("捕获异常:",err)

# 测试用例2:负数年龄(触发数值异常ValueError)
print("-----测试用例2:负数年龄-----")
try:
    check_age(-5)
except (TypeError, ValueError) as err:
    print("捕获异常:",err)

# 测试用例3:传入非整数类型(触发类型异常TypeError)
print("-----测试用例3:非整数年龄-----")
try:
    check_age(18.5)
except (TypeError, ValueError) as err:
    print("捕获异常:",err)

2.4 常用内置异常一览表

|---------------------|--------------------|
| 异常类型 | 触发场景 |
| IndexError | 列表、元组下标索引越界 |
| KeyError | 访问字典不存在的 key |
| TypeError | 传入的数据类型错误,函数参数类型不对 |
| ValueError | 类型正确,但数值非法 |
| FileNotFoundError | 打开不存在的文件 |
| AttributeError | 对象没有该属性 / 方法 |
| ZeroDivisionError | 除数等于 0 |

2.5 注意

  1. except 顺序:具体子类异常写前面,通用 Exception 父类写最后;如果 Exception 写最前面,后面所有 except 永远不会触发。

    python 复制代码
    # 错误示范,子类永远不会被捕获
    # except Exception:
    # except ValueError:
  2. 禁止裸写except:,不写异常类型会捕获所有包括内存崩溃等系统异常,掩盖 bug;

  3. finally 块中如果写 return,会覆盖 try、except 里面 return 返回的值;

  4. else 不要放资源清理逻辑,清理逻辑统一交给 finally;

  5. try 块范围尽量小,只包裹真正可能报错的代码,不要把一大段无关代码全部塞进去。

2.6 使用场景

文件读写关闭文件、网络请求捕获断网异常、用户输入校验、接口参数校验,保障程序鲁棒性。


三、面向对象编程 OOP

3.1 OOP 基础概念

面向对象把程序看作一个个对象的交互,两大基础概念:

  • 类 (class) :抽象模板,描述一类事物共同属性和行为;

  • 对象 (类的实例 instance):类实例化出来的真实个体。

面向对象三大核心特性:封装、继承、多态

3.2 类的定义、实例化、self、__init__

python 复制代码
class Student:
    # __init__:实例初始化方法,实例创建完成自动调用,用来初始化实例属性
    def __init__(self,name,age,gender):
        # self代表当前这个实例对象本身,必须作为实例方法第一个形参
        self.name = name    #实例属性,每个对象独立拥有
        self.age = age
        self.gender = gender

    #实例方法:第一个参数必须self,只能对象调用
    def show_info(self):
        print(f"姓名:{self.name} 年龄:{self.age} 性别:{self.gender}")

    def birthday(self):
        self.age +=1
        print(f"{self.name}过生日,现在{self.age}岁")

#实例化,自动调用__init__
s1 = Student("张三",19,"男")
s2 = Student("莉莉",18,"女")

s1.show_info()
s1.birthday()
s2.show_info()

#读取实例属性
print(s1.name)

注意:__init__不是构造函数;__new__才是真正负责创建对象的构造方法,__init__仅仅对已经创建完成的对象赋值属性。

3.3 访问控制:公有、保护、伪私有

Python 没有真正的访问权限修饰符 (private/public),依靠命名约定实现访问控制:

python 复制代码
class Person:
    def __init__(self):
        self.public_name = "公开成员"      #公开:外部可以随意读写
        self._protect_addr = "约定保护"  #单下划线:约定外部不要直接访问,只是规范,语法不阻止访问
        self.__secret_pwd = "666888"     #双下划线:名字改写伪私有

p = Person()
print(p.public_name)
print(p._protect_addr)

# print(p.__secret_pwd) #直接访问报错
print(p._Person__secret_pwd) #名字改写后可以强行访问,业务代码禁止这样写
  • __xxx双下划线:Python 内部改名为_类名__属性名,防止子类覆盖属性,不是绝对安全加密。

3.4 类属性 vs 实例属性(高频坑)

python 复制代码
class Demo:
    count = 0 #【类属性】属于类本身,所有对象共享

    def __init__(self):
        Demo.count += 1
        self.data = [] #【实例属性】每个对象独立一份

d1 = Demo()
d2 = Demo()
print(Demo.count)

# ❗类属性不要直接赋值可变对象(list dict)
class BadDemo:
    lst = [] #所有实例共享同一个列表!

b1 = BadDemo()
b2 = BadDemo()
b1.lst.append(10)
print(b2.lst) # b2也看到10

# ✅【正确版】可变对象放 __init__ 里(实例独有)
class GoodDemo:
    # 每个对象创建时,单独生成一个全新空列表
    def __init__(self):
        self.lst = []  

# 两个独立对象,各自拥有自己的列表
g1 = GoodDemo()
g2 = GoodDemo()

# 单独给 g1 的列表添加 10
g1.lst.append(10)

# 分别打印两个对象的列表
print("正确写法 g1:", g1.lst) # [10] 自己的数据
print("正确写法 g2:", g2.lst) # []   完全不受影响,互不干扰

3.5 继承

子类复用父类代码,并且可以扩展新功能,语法class 子类(父类):

python 复制代码
#父类
class Animal:
    def __init__(self,name):
        self.name = name
    def eat(self):
        print(f"{self.name}吃东西")

#子类Dog继承Animal
class Dog(Animal):
    def bark(self):
        print(f"{self.name}汪汪叫")

dog = Dog("大黄")
dog.eat() #继承父类eat方法
dog.bark()

3.5.1方法重写

子类重写父类同名方法,覆盖原有逻辑;使用super()调用父类方法。

python 复制代码
class Animal:
    def __init__(self,name):
        self.name = name
    def speak(self):
        pass

class Cat(Animal):
    def __init__(self,name,color):
        #调用父类__init__,复用父类初始化逻辑
        super().__init__(name)
        self.color = color #扩展子类自己的属性

    #重写父类speak
    def speak(self):
        print(f"{self.name}:喵喵喵,毛色{self.color}")

cat = Cat("橘猫","黄色")
cat.speak()

3.5.2多继承

一个类同时继承多个父类。

python 复制代码
class A:
    def test(self):
        print("A")
class B:
    def test(self):
        print("B")

class C(A,B): #多继承
    pass

c = C()
c.test()
print(C.__mro__) #MRO方法解析顺序,查找方法的先后顺序
#✅ 同名方法:左边优先,只执行一个
#✅ 不会两个都执行
#✅ 左边的类优先级高于右边

菱形继承问题,通过类.__mro__查看搜索顺序。

3.6 多态

同一个方法接口,不同子类对象有不同实现,调用时自动匹配对应对象的实现。

同一个形态,多种状态

  • 统一入口:都是调用 speak() 方法(同一个形态)

  • 不同效果:狗汪汪叫、猫喵喵叫(多种执行状态)

python 复制代码
class Animal:
    # 父类统一规范:定义统一方法,不实现具体逻辑(抽象规范)
    def speak(self):
        pass

class Dog(Animal):
    # 子类重写父类方法:专属实现
    def speak(self):
        print("汪汪")

class Cat(Animal):
    # 子类重写父类方法:专属实现
    def speak(self):
        print("喵喵")

# 统一入口函数:父类接收所有子类对象,实现多态
def make_sound(obj:Animal):
    # 传入不同子类对象,自动执行对应子类的方法
    obj.speak()

# 多态效果:同一个函数,不同对象,不同结果
make_sound(Dog())  # 传入狗对象 → 执行狗的方法
make_sound(Cat())  # 传入猫对象 → 执行猫的方法

多态、多继承中出现的 object ,是 Python 所有类的顶层祖宗类

  • 我们自己写的所有类,默认自动继承 object,不用手动写

  • __mro__ 查找顺序最后出现 object,代表所有方法查找的终极兜底

3.7 实例方法、类方法、静态方法三者完整对比

3.7.1 实例方法

1、定义

写在类中、无装饰器 、第一个参数必须是 self 的方法,叫做实例方法。

2、核心特性

  • 第一个参数 self:代表当前实例对象,调用时系统自动传参

  • 权限最大:既能读取/修改「实例属性」,也能读取/修改「类属性」

  • 只能由对象调用(不推荐类名调用)

3、适用场景

绝大多数场景!只要是描述对象个体行为(学生吃饭、人说话、动物跑)全部用实例方法。

4、示例

python 复制代码
class Student:
    # 类属性(所有对象共享)
    school = "第一中学"

    def __init__(self, name, age):
        # 实例属性(每个对象自己独有)
        self.name = name
        self.age = age

    # 实例方法
    def show_info(self):
        # 既能用实例属性,也能用类属性
        print(f"学校:{Student.school},姓名:{self.name},年龄:{self.age}")

# 必须实例化对象调用
s1 = Student("小明", 18)
s1.show_info()

5、注意

  • self 不能省略、不能改名(不能写成 this)

  • 实例方法必须通过对象调用,不能直接用类名无脑调用


3.7.2 类方法(@classmethod)

1、定义

@classmethod 装饰、第一个参数必须是 cls 的方法,叫做类方法。

2、核心特性

  • 第一个参数 cls:代表当前「类本身」,自动传递类名

  • 只能访问类属性、类方法绝对不能访问实例属性、self

  • 调用方式灵活:类名调用 / 对象调用 都可以

3、适用场景

操作整个类的公共数据、统一修改所有对象共享的属性、工厂方法创建对象。

4、示例

python 复制代码
class Student:
    # 类属性:公共数据
    school = "第一中学"

    # 类方法
    @classmethod
    def change_school(cls, new_school):
        # cls 等价于 Student 类
        cls.school = new_school
        print(f"统一修改学校为:{cls.school}")

# 类名直接调用(推荐)
Student.change_school("第二中学")

# 对象也能调用(不推荐)
s1 = Student()
s1.change_school("第三中学")

print(Student.school)

5、注意

  • 类方法里 绝对不能出现 self,会直接报错

  • 只能改公共类属性,改不了某个对象的独有数据


3.7.3 静态方法(@staticmethod)

1、定义

@staticmethod 装饰、没有默认参数(无self、无cls) 的方法,叫静态方法。

2、核心特性

  • 和「类、对象」基本无关,就是一个放在类里面的普通工具函数

  • 不能访问实例属性、不能访问类属性

  • 类名/对象都可以调用

3、适用场景

纯粹的工具计算、数据处理、格式转换,不需要用到类和对象的任何属性

4、示例

python 复制代码
class Calc:
    # 静态方法:纯粹工具计算,和类、对象无关
    @staticmethod
    def add_num(a, b):
        return a + b

# 直接类名调用(推荐)
print(Calc.add_num(10, 20))

# 对象也能调用
c = Calc()
print(c.add_num(30, 40))

|------|---------------|-------|--------------|-----------|
| 类型 | 装饰器 | 第一个参数 | 可访问内容 | 调用方式 |
| 实例方法 | 无 | self | 实例属性、类属性 | 对象调用 |
| 类方法 | @classmethod | cls | 类属性,不能访问实例属性 | 类名 / 对象调用 |
| 静态方法 | @staticmethod | 无 | 不能访问类、实例属性 | 类名 / 对象调用 |

相关推荐
神经蛙199615 小时前
🌍 别再硬编码中文了!Python Web 项目国际化(i18n)完全指南
后端·python
颜酱15 小时前
14 | 验证并修正 LLM 生成的 SQL
人工智能·python
颜酱15 小时前
13 | 使用 LangChain 生成 SQL
人工智能·python·langchain
春生野草16 小时前
个人笔记——C语言字符串、树
c语言·开发语言·笔记
风中芦苇啊16 小时前
Java EasyExcel 导入通用工具类:自定义注解映射字段 + 反射机制
java·开发语言
PieroPc16 小时前
Python 写的 Windows凭据添加工具 第二版 解决Win11 23H2, 25H2,26H1,共享文件和打印 一部份问题,不是全部!
开发语言·windows·python
颜酱16 小时前
12 | 组装 SQL 生成上下文
人工智能·python
家有娇妻张兔兔16 小时前
Java 对接 PLC 主流型号最合适的方案:Apache PLC4X 实战指南
java·开发语言·plc·modbus·数据缓存·西门子s7·apache plc4x
The_Ticker16 小时前
大宗商品行情API接入教程
开发语言·python·websocket·程序人生·区块链
用户83562907805116 小时前
如何使用 Python 合并多个 Excel 文件
后端·python