初识Python面向对象

一、引言:从杂乱的数据到规整的结构

在生活中,我们习惯于用"表格"来组织信息------入学登记表、员工信息表、商品清单......表格让杂乱的数据变得清晰有序。

在程序中,我们同样需要这种"规整"的数据组织方式。试想一下:如果要记录一名学生的姓名、年龄、班级、成绩等信息,用变量当然可以,但如果有100个学生,难道要定义100组变量吗?用列表或字典也可以,但数据结构松散,容易出错。

面向对象编程(Object-Oriented Programming, OOP) 正是为了解决这个问题而生的。它让我们可以在程序中设计"表格"(类) ,然后生产"表格"(对象) ,最后填写数据(属性赋值) ,完美模拟现实世界的数据组织方式。

本篇博客将带领大家从零开始,全面掌握Python面向对象编程的核心知识,包括类与对象、封装、继承、多态、类型注解等。

二、初识对象

2.1 现实世界 vs 程序世界

在现实世界中,生产一件产品通常遵循这样的流程:

  1. 设计图纸:画出产品的结构和功能

  2. 生产实体:根据图纸制造出实际产品

  3. 投入使用:产品完成实际工作

在程序世界中,面向对象编程遵循完全相同的逻辑:

  1. 设计类(Class) :定义数据的结构和行为

  2. 创建对象(Object) :根据类实例化出具体对象

  3. 使用对象:调用对象的方法完成功能

2.2 类的定义与对象的创建

类(Class) 是"图纸",定义了属性和行为。对象(Object) 是"实体",是基于类创建的具体实例。

python 复制代码
# 定义一个学生类(设计图纸)
class Student:
    # 成员变量(属性)
    name = None
    age = None
    
    # 成员方法(行为)
    def say_hi(self):
        print(f"大家好,我叫{self.name}!")

# 创建对象(生产实体)
stu = Student()
stu.name = "张三"      # 填写属性
stu.say_hi()           # 调用方法

三、成员变量与成员方法

3.1 成员变量(属性)

在类中定义的变量称为成员变量,用于存储对象的数据。每个对象都有自己的成员变量副本,互不干扰。

3.2 成员方法(行为)

在类中定义的函数称为成员方法 ,用于描述对象的行为。成员方法与普通函数的区别在于:第一个参数必须是self

3.3 self关键字

self是成员方法定义时必须填写的参数,它代表对象自身

python 复制代码
class Student:
    name = None
    
    def say_hi(self):
        # self.name 访问当前对象的name属性
        print(f"大家好,我叫{self.name}!")
    
    def say_hi2(self, msg):
        print(f"大家好,我叫{self.name},{msg}")

# 使用
stu = Student()
stu.name = "里斯"
stu.say_hi()              # self自动传入,无需手动传参
stu.say_hi2("欢迎学习Python!")

四、构造方法(init

4.1 什么是构造方法?

__init__是Python类中的构造方法 ,在创建对象时会自动执行 ,主要用于初始化对象的属性

python 复制代码
class Student:
    # 构造方法
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print(f"学生{name}创建成功!")

# 创建对象时自动调用__init__
stu = Student("张三", 18)   # 输出:学生张三创建成功!

构造方法的特点

  • 方法名必须是__init__(前后各两个下划线)

  • 第一个参数必须是self

  • 创建对象时自动调用

  • 传入的参数会自动传递给__init__

4.2 构造方法的优势

使用构造方法后,我们可以在创建对象的同时完成属性赋值,代码更简洁。

python 复制代码
# 不使用构造方法(传统方式)
stu = Student()
stu.name = "张三"
stu.age = 18

# 使用构造方法(推荐)
stu = Student("张三", 18)   # 一步到位

五、内置魔法方法

Python类中有一些以双下划线开头和结尾的特殊方法,被称为魔法方法。它们会在特定情况下自动被调用。

5.1 str:字符串方法

控制对象被打印时的显示格式。

python 复制代码
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return f"【学生姓名:{self.name},年龄:{self.age}】"

stu = Student("张三", 18)
print(stu)   # 【学生姓名:张三,年龄:18】

5.2 lt:小于比较

控制对象使用<运算符时的行为。

python 复制代码
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __lt__(self, other):
        return self.age < other.age

stu1 = Student("张三", 18)
stu2 = Student("王五", 22)
print(stu1 < stu2)   # True(按年龄比较)

5.3 eq:等于比较

控制对象使用==运算符时的行为。

python 复制代码
def __eq__(self, other):
    return self.age == other.age

stu1 = Student("张三", 18)
stu2 = Student("李四", 18)
print(stu1 == stu2)   # True(年龄相同)

六、封装

6.1 什么是封装?

封装是面向对象三大特性之一(封装、继承、多态)。它指的是将属性和行为封装在类中,并对用户隐藏某些内部细节。

现实世界中的事物,并不是所有属性和行为都是公开的。比如手机的内部电路、操作系统的内核代码,用户不需要知道,也不应该随意访问。

6.2 私有成员

在Python中,使用双下划线开头 的变量或方法,表示私有成员,只能在类内部使用,外部无法访问。

python 复制代码
class Phone:
    # 私有成员变量
    __brand = "华为"
    __voltage = 4.0
    
    # 私有成员方法
    def __check_voltage(self):
        if self.__voltage < 5:
            print("电压不足")
    
    # 公开方法
    def call(self):
        self.__check_voltage()   # 内部可以调用私有方法
        print("正在通话中")

phone = Phone()
# print(phone.__brand)   # 错误!私有成员外部不可访问
# phone.__check_voltage()  # 错误!
phone.call()              # 正确!公开方法可以访问私有成员

封装的意义:保护数据安全,隐藏实现细节,提供清晰的外部接口。

七、继承

7.1 单继承

继承允许子类获得父类的所有成员变量和方法(私有成员除外),实现代码复用。

python 复制代码
# 父类
class Phone:
    producer = "华为"
    
    def call(self):
        print("正在通话中")

# 子类(单继承)
class Phone2025(Phone):
    def call_6G(self):
        print("正在6G通话中")

# 使用
phone = Phone2025()
print(phone.producer)   # 华为(继承自父类)
phone.call()            # 正在通话中(继承自父类)
phone.call_6G()         # 正在6G通话中(自己的)

7.2 多继承

Python支持多继承,一个子类可以继承多个父类。

python 复制代码
class NFCReader:
    producer = "苹果工厂1"
    def read(self):
        print("正在读取数据")

class RemoteControl:
    producer = "苹果工厂2"
    def control(self):
        print("正在遥控")

# 多继承
class MyPhone(NFCReader, RemoteControl):
    pass

my_phone = MyPhone()
print(my_phone.producer)   # 苹果工厂1(优先继承第一个父类)
my_phone.read()            # 正在读取数据
my_phone.control()         # 正在遥控

多继承的同名冲突 :当多个父类有同名成员时,按继承顺序从左到右,优先保留先继承的。

7.3 pass占位语句

pass是Python中的占位语句,用于保证代码结构的完整性,表示暂时为空,稍后补充。

python 复制代码
class MyPhone(NFCReader, RemoteControl):
    pass   # 暂时不写任何内容,保持类定义完整

八、复写父类成员与super()

8.1 复写(Override)

如果子类对父类的成员不满意,可以在子类中重新定义同名的成员,覆盖父类的版本。

python 复制代码
class Phone:
    producer = "SJ"
    def call(self):
        print("正在通话中")

class MyPhone(Phone):
    # 复写父类属性
    producer = "PYT"
    # 复写父类方法
    def call(self):
        print("正在5G通话中")
        print("5G升级中!")

my_phone = MyPhone()
print(my_phone.producer)   # PYT(子类的值)
my_phone.call()            # 正在5G通话中(子类的方法)

8.2 调用被复写的父类成员

在子类中,如果复写了父类成员,但仍需使用父类的版本,有两种方式:

python 复制代码
class MyPhone(Phone):
    def call(self):
        print("正在5G通话中")
        
        # 方式1:使用父类名调用
        Phone.call(self)
        print(f"父类的厂商:{Phone.producer}")
        
        # 方式2:使用super()调用
        super().call()
        print(f"父类的厂商:{super().producer}")

九、类型注解

9.1 为什么需要类型注解?

Python是动态类型语言,变量的类型在运行时才确定。这在带来灵活性的同时,也让代码的可读性IDE提示受到影响。

类型注解可以显式地说明变量、函数参数和返回值的类型,帮助IDE提供更好的代码提示,也方便其他开发者理解代码。

9.2 变量的类型注解

python 复制代码
# 基本类型注解
a: int = 10
name: str = "张三"
price: float = 9.9
is_ok: bool = True

# 容器类型注解
my_list: list[int] = [1, 2, 3, 4]
my_tuple: tuple[int, str] = (1, "hello")
my_dict: dict[str, int] = {"age": 18}

# 类对象注解
class Student:
    pass
stu: Student = Student()

9.3 函数(方法)的类型注解

python 复制代码
# 参数类型注解 + 返回值类型注解
def add(x: int, y: int) -> int:
    return x + y

result = add(1, 2)   # IDE会提示result是int类型

9.4 Union类型

当变量可能是多种类型之一时,使用Union

python 复制代码
from typing import Union

# 列表中的元素可以是int或str
my_list: list[Union[int, str]] = [1, 2, "3", "4"]

# 函数参数可以是int或str,返回值也可以是int或str
def process(data: Union[int, str]) -> Union[int, str]:
    return data

类型注解的特点

  • 仅仅是提示性的,不是强制性的

  • 不会影响程序的运行

  • 主要作用是提高代码可读性和IDE支持

十、多态与抽象类

10.1 什么是多态?

多态(Polymorphism)是指同一个行为(方法),传入不同的对象,得到不同的状态和结果。

python 复制代码
class Animal:
    def speak(self):
        pass   # 抽象方法

class Dog(Animal):
    def speak(self):
        print("汪汪汪")

class Cat(Animal):
    def speak(self):
        print("喵喵喵")

def make_noise(animal):
    animal.speak()   # 传入不同对象,发出不同声音

make_noise(Dog())   # 汪汪汪
make_noise(Cat())   # 喵喵喵

10.2 抽象类(接口)

抽象类是包含抽象方法的类,它定义了"有哪些方法",但不实现具体细节,由子类自行决定如何实现。

在Python中,抽象方法的方法体通常写为pass

python 复制代码
class AC:
    def cool_wind(self):
        """制冷"""
        pass
    
    def hot_wind(self):
        """制热"""
        pass

class GREE(AC):
    def cool_wind(self):
        print("格力制冷")
    def hot_wind(self):
        print("格力制热")

class Midea(AC):
    def cool_wind(self):
        print("美的制冷")
    def hot_wind(self):
        print("美的制热")

抽象类的设计思想

  • 父类定义标准(有哪些方法)

  • 子类实现细节(如何实现)

  • 面向接口编程,而非具体实现

十一、综合实战:学生信息录入系统

综合运用类、构造方法、__str__、列表等知识,完成一个学生信息录入系统。

python 复制代码
class Student:
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address
    
    def __str__(self):
        return f"【学生姓名:{self.name},年龄:{self.age},地址:{self.address}】"

def main():
    students = []
    total = 3
    
    for i in range(total):
        print(f"当前录入第{i+1}位学生信息,总共需录入{total}位")
        name = input("请输入学生姓名:")
        age = input("请输入学生年龄:")
        address = input("请输入学生地址:")
        
        stu = Student(name, age, address)
        students.append(stu)
        print(f"学生{i+1}信息录入完成:{stu}")
    
    print("\n所有学生信息如下:")
    for student in students:
        print(student)

if __name__ == "__main__":
    main()

十二、总结

本篇博客系统学习了Python面向对象编程的核心知识:

主题 核心内容
类与对象 类是图纸,对象是实体
成员方法 必须包含self参数
构造方法 __init__,创建对象时自动执行
魔法方法 __str____lt____eq__
封装 私有成员以__开头,外部不可访问
继承 单继承、多继承,pass占位
复写 子类重定义父类成员,super()调用父类
类型注解 变量、函数参数、返回值、Union
多态 同一行为,不同对象产生不同状态
抽象类 父类定义标准,子类实现细节

面向对象编程让我们的程序更加结构化、易维护、易扩展。它模拟了现实世界的事物组织方式,是大型项目开发中不可或缺的编程范式。

相关推荐
用户3126874877201 小时前
ThreadLocal 到底会不会内存泄漏?源码级拆解 + 线程池陷阱
java
研☆香1 小时前
js中 onload 事件的用法
开发语言·javascript·ecmascript
珍珠先生1 小时前
P11 · MySQL 驱动版本过旧:Client does not support authentication protocol
java
~木雨1 小时前
Java 并发编程架构全景:并发层的五域设计 —— 线程模型、线程池隔离、并发安全到问题治理(全体系汇总)
java·安全·架构·线程池·并发编程·高并发架构
xiancai_xianyu2 小时前
想把数据模型一次建完美再上AI?会一直卡在建模里
开发语言·人工智能·php·数据模型·语义层·本体建模·企业知识网络
极小狐2 小时前
从复制粘贴到可复用组件:极狐GitLab CI/CD 组件目录实战
java·ci/cd·gitlab·devops·组件化
麻瓜code2 小时前
【Agent】Spring AI RAG 实战:本地向量库 + 云端知识库
java·人工智能·spring
(Charon)2 小时前
【C++】网络缓冲区设计(二):Ring Buffer环形缓冲区、head/tail与跨界读写
开发语言·c++
Java后端的Ai之路2 小时前
LangChain Deep Agents 从入门到企业实战
开发语言·人工智能·python·langchain·deepagents