⌨️ 第五章 从设计到测试
📄 本篇摘要

面向对象的地基三词:类(class)=图纸;实例(instance)=按图纸造出的具体产品;对象(object)=实例的别名(口语中常混用)。类把数据(属性)和操作(方法)装进一个盒子——面向对象三大特性(封装、继承、多态)都从这个盒子出发。

📝 关系

上一节:构建与 make | 下一节:继承与多重继承

一、类是图纸,实例是产品

        类 class(图纸)                实例 instance(产品)
   ┌─────────────────┐          ┌──────────────────┐
   │ Dog             │   new    │ 旺财 (name=旺财)  │
   │ 属性: name      │ ──────>  │ 小黑 (name=小黑)  │
   │ 方法: bark()    │          │  ……(各自独立)   │
   └─────────────────┘          └──────────────────┘

类定义一次,实例可以造无数个——每个实例的属性值各自独立,方法共用同一份定义。这就是面向对象和散装变量的本质区别:数据和行为长在一起,旺财.bark() 而不是 bark(旺财的名字)。

二、三大特性总览(本章后半章逐一展开)

教材提示:三大特性不是教条,是管理复杂度的工具——程序小时随便写,程序大了靠它们分而治之。

三、动手 Demo:第一张图纸

class Dog:
    """图纸:狗 = 名字 + 叫"""
    species = "犬科"                     # 类变量:所有实例共享

    def __init__(self, name, age):       # 造实例时的初始化(5-25 展开)
        self.name = name                 # 实例变量:每只狗独立
        self.age = age

    def bark(self):                      # 方法
        return f"{self.name}({self.age}岁): 汪!"

    def birthday(self):                  # 方法操作自己的数据
        self.age += 1
        return self.age

# 图纸 -> 产品
wangcai = Dog("旺财", 3)
xiaohei = Dog("小黑", 1)

print(wangcai.bark())
print(xiaohei.bark())
print(Dog.species, "==", wangcai.species)    # 类变量大家共享
print(wangcai.birthday(), wangcai.birthday())  # 只动了旺财的年龄

# 验证【属性独立】:旺财过生日,小黑没变
print(xiaohei.age)

沙箱实跑输出:

旺财(3岁): 汪!
小黑(1岁): 汪!
犬科 == 犬科
4 5
1

看到什么算成功:两只狗叫声里名字年龄各归各;旺财连过两个生日到 5 岁,小黑还是 1。

读结果:species 是类变量(所有狗共享一份),name/age 是实例变量(每只狗一份)——共享与独立的分界是面向对象的第一课。birthday 方法改的是自己的数据:数据与操作长在一起的活例证。

四、30 秒实验

把 species 改赋值到实例上(wangcai.species = "特俗品种")再打印 xiaohei.species——小黑仍是犬科。实例赋值只造了旺财自己的副本,类变量本体没动(遮蔽现象,和 4-6 作用域同款逻辑)。

五、常见误区

误区 真相
类和对象是一个东西 类是图纸(存在于代码里),对象是运行时造出的产品
方法一定要传一堆参数 方法自带 self——数据和行为长在一起,不必东拼西凑
实例变量和类变量随便混用 共享的(常量、计数器)用类变量,独立的用实例变量;混用出诡异 bug
自测三问(点击展开) 1. **类、实例、对象三词的关系?** 答:类是图纸;实例是按图纸造出的产品;对象基本是实例的同义词。 2. **`__init__` 什么时候执行?** 答:每次 new 一个实例时执行,负责初始化该实例自己的属性。 3. **类变量和实例变量的取舍?** 答:所有实例共享的用类变量,各实例独立的用实例变量。

相关笔记