Python 从零开始 · 第 10 课:面向对象——让代码更像真实世界
前面我们写的函数,都是"一堆散装的动作"。但真实世界不是这么组织的——真实世界里是一个个对象:一只猫、一辆车、一个账户。
对象有自己的数据(猫的颜色、车的速度),也有自己的行为(猫会叫、车会跑)。
面向对象编程(OOP),就是让代码也用这种"对象"的方式组织。这是从"写脚本"到"写程序"的分水岭。
一、类(class):对象的"图纸"
class 是创建对象的模板,就像"猫"这个物种的图纸。先定义图纸,再造出具体的猫:
class Cat:
def __init__(self, name, color): # 构造方法:造猫时自动执行
self.name = name # 把数据挂到对象上
self.color = color
def meow(self): # 方法:对象的行为
print(f"{self.name} 喵喵叫")class Cat:定义了一个叫 Cat 的类。__init__是构造方法,造对象时自动跑,用来初始化数据。self代表"这个对象自己",self.name就是"这个对象的 name"。
🧊 冷笑话:"Python 为什么要去上学?""为了提升它的class(类 / 班级)。"——class在 Python 里是"类",英文里又是"班级",一举两得。
二、造对象、用对象
cat1 = Cat("小黑", "黑色") # 造一只叫小黑的猫
cat2 = Cat("小白", "白色") # 再造一只
print(cat1.name) # 小黑
print(cat2.color) # 白色
cat1.meow() # 小黑 喵喵叫
cat2.meow() # 小白 喵喵叫同一个类,可以造出无数个对象,每个对象的数据各自独立。
三、self 到底是谁?
self 不是关键字,只是一个约定俗成的名字,代表"调用方法的那个对象"。cat1.meow() 时,self 就是 cat1;cat2.meow() 时,self 就是 cat2。
所以 self.name 才能分别拿到"小黑"和"小白"。
四、一个更实用的例子:银行账户
class Account:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
def deposit(self, amount): # 存钱
self.balance += amount
print(f"存入 {amount},余额 {self.balance}")
def withdraw(self, amount): # 取钱
if amount > self.balance:
print("余额不足")
else:
self.balance -= amount
print(f"取出 {amount},余额 {self.balance}")
acc = Account("张三", 1000)
acc.deposit(500) # 存入 500,余额 1500
acc.withdraw(200) # 取出 200,余额 1300
acc.withdraw(9999) # 余额不足数据(余额)和行为(存/取)被"打包"进了同一个对象,逻辑清晰多了。
五、继承:子类复用父类
继承让一个类"继承"另一个类的数据和方法,避免重复:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print(f"{self.name} 发出了声音")
class Dog(Animal): # Dog 继承 Animal
def speak(self): # 覆盖(重写)父类的方法
print(f"{self.name} 汪汪叫")
class Cat(Animal):
def speak(self):
print(f"{self.name} 喵喵叫")
dog = Dog("旺财")
dog.speak() # 旺财 汪汪叫class Dog(Animal):Dog 继承 Animal,自动拥有__init__里的self.name。- 子类可以重写父类方法(speak 各自不同)。
继承的精髓:把公共的东西放父类,子类只写差异部分。
六、封装:把数据藏起来
面向对象强调"数据不应该被随便改"。Python 用下划线约定"这是私有属性,别碰":
class Account:
def __init__(self, owner, balance=0):
self.owner = owner
self._balance = balance # 下划线开头:约定"私有"
def get_balance(self):
return self._balance # 通过方法访问,而不是直接摸
def deposit(self, amount):
if amount > 0:
self._balance += amountPython 的"私有"是约定而非强制(不像 Java),靠自觉和规范,而不是靠编译器拦你。
七、什么时候用类?什么时候用函数?
- 函数:一个独立的小动作,输入→输出。适合"算个平方""读个文件"。
- 类:有"数据 + 操作数据的行为",且这些要打包在一起、可能要多个实例。适合"账户""用户""游戏角色"。
简单场景别硬上类,函数就够;数据和行为紧密耦合时,用类更清晰。
八、动手时间 🎯
实验 1:学生类
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def grade(self):
if self.score >= 90:
return "A"
elif self.score >= 70:
return "B"
elif self.score >= 60:
return "C"
return "D"
s = Student("张三", 85)
print(s.name, s.grade()) # 张三 B实验 2:继承实战——形状求面积
class Shape:
def area(self):
return 0
class Circle(Shape):
def __init__(self, r):
self.r = r
def area(self):
return 3.14 * self.r * self.r
class Rectangle(Shape):
def __init__(self, w, h):
self.w = w
self.h = h
def area(self):
return self.w * self.h
print(Circle(5).area()) # 78.5
print(Rectangle(3, 4).area()) # 12实验 3:待办事项类
class TodoList:
def __init__(self):
self.items = []
def add(self, item):
self.items.append(item)
print(f"已添加:{item}")
def done(self, index):
removed = self.items.pop(index)
print(f"已完成:{removed}")
def show(self):
for i, item in enumerate(self.items):
print(f"{i}. {item}")
todo = TodoList()
todo.add("学 Python")
todo.add("写作业")
todo.show()
todo.done(0)九、小结
class是图纸,对象是造出来的实例;__init__初始化数据,self代表对象自己。- 方法 = 打包在类里的函数,把"数据 + 行为"捆在一起,逻辑更清晰。
- 继承复用公共代码、重写体现差异;下划线开头是"私有"约定;简单场景别硬上类。
下一课,我们学 进阶语法与函数式编程——生成器、装饰器、map/filter,这些是读懂高手代码、写出优雅代码的钥匙。
先把「银行账户」和「形状求面积」敲熟,面向对象的手感就长在你脑子里了。