🔍
✦ 38 个知识实体 · 48 条逻辑连线 | 悬浮查看关联 · 鼠标拖拽漫游 · 点击节点查看知识卡片

Day 09 · 面向对象思想与核心底层机制随堂精要

01 · 编程思想概述

思想是思考问题的方式,能直接决定具体的编码行为。编程思想则是指在编程过程中面对复杂需求时,分析与解决问题的方法论。

1. 面向过程 (POP - Procedure Oriented)

核心口诀:「凡事必躬亲」

  • 更侧重于步骤与过程的把控
  • 典型代表语言:C 语言
  • 生活栗子:比如洗衣服,需要自己亲自「泡一泡 ➔ 搓一搓 ➔ 拧一拧 ➔ 晾一晾」。

2. 面向对象 (OOP - Object Oriented)

核心口诀:「自己的事情别人做,找对象解决问题」

  • 更侧重于对象的使用与职能划分
  • 典型代表语言:Java、C++、Python
  • 生活栗子:洗衣服找「洗衣机」对象,把衣服放进去,按启动即可!
💡 为什么面向对象思想最符合人类的直觉?

因为我们从出生到现在,一直在用面向对象的思维解决生活中的问题(饿了找外卖APP对象,去上学找学校对象)。《Thinking In Java》中有一句经典名言:「万物皆对象」。对象是能帮助你解决具体问题的事物,它不仅指现实实体,在代码世界里抽象的数据结构、模块和功能实体皆为对象。

02 · 类和对象的关系

在面向对象体系中,类与对象是不可分割的核心概念:

🏗️ 类 (Class)

一类事物的抽象与图纸:只要是一个名词,代表一种类别或类型(如 StudentCarPerson)。

📦 对象 (Instance)

此类事物的具体化产物:根据图纸制造出来的具体产品(如具体的学生「张三」、一辆具体的特斯拉)。

📌 是先有类还是先有对象?

类是对象的模板,对象是根据类生产出来的具体实例。 我们日常写业务代码,真正干活、调用方法、操作属性的,正是具体的对象

03 · 如何创建类和根据类创建对象

在 Python 中,通常使用事物描述类(Bean 类)来建模现实业务。类命名严格遵守大驼峰(PascalCase)规范:

Python 类定义结构
class 类名:
    """类的说明文档,可通过 类名.__doc__ 访问"""
    类属性 = 初始值       # 类变量,全类共享
    
    def __init__(self, 形参1, 形参2):
        self.形参1 = 形参1  # 实例属性
        self.形参2 = 形参2

    def 实例方法名(self):
        pass

学生类 (Student) 完整实战案例

Student 案例代码
class Student:
    """描述学生这类事物的类"""
    school = "atguigu"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self, food):
        print(f"姓名是 : {self.name} , 年龄是 : {self.age} 的学生在吃 {food}")

# 使用案例
stu1 = Student("张三", 18)
print(stu1.name)            # 张三
stu1.eat("汉堡")            # 语法糖调用
Student.eat(stu1, "肉夹馍") # 本质调用

04 · 深度分析 __init__ 与 __new__ 函数

⚠️ 高频考点:谁才是真正的「对象创建者」?

__new__(cls)真正负责向内存申请空间、创建出实例对象的构造函数!必须返回创建出来的对象实例;
__init__(self):是对象的初始化函数。它接收 __new__ 返回的全新对象引用(即 self),负责对其属性进行一一赋值,不能有任何返回值

__new__ 与 __init__ 交互时序图
图 1 · __new__() 与 __init__() 函数执行时序与堆内存分配流向

05 · 类和对象使用的内存图解

理解 Python 面向对象的底层精髓,必须直观建立栈内存 (Stack)、堆内存 (Heap) 与方法区 (Method Area) 的映射关系:

  • 方法区:加载类的字节码,存储类属性(如 school)与类中所有方法的代码块;
  • 堆内存 (Heap):由 __new__ 分配具体对象所占的独立空间,包含各个对象独有的 __dict__ 实例属性及指向所属类的引用;
  • 栈内存 (Stack):存储函数调用栈帧及局部变量(如 stu1),变量本质上是指向堆内存对象物理地址的指针。
Python 类和对象底层内存图
图 2 · 类与对象底层内存分配结构示意图(方法区 / 堆 / 栈)

06 · self 的理解和用法

🪞 形象记忆:self 就是「照镜子」

self 只能在类中使用。哪个具体的对象调用了这个带有 self 参数的方法,那这个方法内部的 self 指向的就是谁!

self 调用示例
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def study(self):
        print(f"{self.name} is studying hard!")

    def show(self):
        print(f"My name is {self.name}, and I am {self.age} years old.")
        self.study() # 在实例方法内调用自身的其他实例方法,需要带上 self.

p1 = Person("Alice", 20)
p1.show()

07 · 属性的操作(类属性 vs 实例属性)

🚨 类属性修改必须防范的坑点!

正确修改类属性:必须使用 类名.类属性 = 新值
错误做法:若使用 对象名.类属性 = 新值,实际上是在该对象内部强行动态新建了一个同名的实例属性,产生遮蔽,底层类属性根本未变!

类属性修改陷阱实测
class Person:
    school = "尚硅谷"

p1 = Person()
p2 = Person()

p1.school = "北京大学" # 仅给 p1 自身添加了同名实例属性
print(Person.school)  # 输出: 尚硅谷 (未变)
print(p1.school)      # 输出: 北京大学
print(p2.school)      # 输出: 尚硅谷

# 正确方式:
Person.school = "五道口职业技术学院"
print(p2.school)      # 输出: 五道口职业技术学院

08 · 方法的操作与分类

1. 实例方法 (Instance Method)

方法第一个形参必须是 self。既能读写实例属性,也可以访问类属性。

2. 类方法 (@classmethod)

使用 @classmethod 声明,首形参为 cls。只能读写类属性,无法访问任何实例属性。推荐直接通过 类名.类方法() 调用。

3. 静态方法 (@staticmethod)

使用 @staticmethod 声明,形参里既没有 self 也没有 cls。在逻辑上属于类的纯工具函数,完全依赖传入的实参。

4. 在类外定义函数并挂载

Python 允许将类外的普通函数赋值给类属性,挂载后带有 self 形式参数的函数可作为实例方法正常被调用。