面向对象
很多初学者第一次看到“面向对象”这四个字,就会紧张,觉得这一定是很高级、很抽象、很难的内容。
实际上,面向对象最核心的目标只有一个:让代码更容易组织。
当你的程序很小时,只写几个函数就够了;但当程序里开始出现“学生”“用户”“商品”“订单”“文章”“爬虫任务”这类带有数据和行为的对象时,只用函数就会越来越乱。这个时候,面向对象就开始有价值了。
所以你不要把这一节理解成“高深理论”,而是把它理解成:一种更适合组织复杂程序的写法。
本节目标
- 理解什么是类和对象
- 理解属性和方法
- 学会使用
__init__ - 理解
self的作用 - 学会创建对象并调用方法
- 理解继承和方法重写
- 建立对面向对象的基本直觉
先修知识
在学习这一节之前,你至少应该已经掌握:
- 变量
- 函数
- 列表和字典
- 条件语句和循环
因为面向对象不是独立于这些基础语法存在的,它只是把这些能力组织得更有结构。
为什么会有面向对象
先看一个没有使用面向对象的例子。
student_name = "小明"
student_age = 18
student_city = "上海"
def study(name):
print(f"{name} 正在学习")
def introduce(name, age, city):
print(f"大家好,我叫{name},今年{age}岁,来自{city}")
study(student_name)
introduce(student_name, student_age, student_city)输出结果:
小明 正在学习
大家好,我叫小明,今年18岁,来自上海这段代码在数据很少时没有问题。但如果学生变成 100 个,你就会发现:
- 变量越来越多
- 相关函数越来越散
- 数据和行为没有被组织在一起
这个时候,我们就希望把“学生的属性”和“学生的行为”放在一起管理。这就是面向对象的出发点。
类和对象到底是什么
你可以先用一个非常直观的比喻理解:
- 类:设计图
- 对象:根据设计图造出来的具体实例
例如:
- “狗”这个概念可以看成类
- 你家里的那只名叫“旺财”的狗,就是对象
再比如:
- “学生”这个抽象概念是类
- “小明”“小红”这些具体学生是对象
第一个类
class Dog:
pass这里定义了一个叫 Dog 的类。
你可以暂时把 class 理解成“创建一个新模板”的关键字。
pass 的意思是“先占个位置,什么都不做”。
创建对象
类定义好以后,就可以根据这个类创建对象。
class Dog:
pass
dog1 = Dog()
dog2 = Dog()
print(dog1)
print(dog2)输出结果示例:
<__main__.Dog object at 0x000001>
<__main__.Dog object at 0x000002>虽然看起来内容有点奇怪,但你至少可以先知道一件事:dog1 和 dog2 是两个不同的对象。
属性:对象“有什么”
属性就是对象身上的数据。
比如一只狗,可能有这些属性:
- 名字
- 年龄
- 颜色
我们可以在对象创建后临时给它加属性:
class Dog:
pass
dog = Dog()
dog.name = "旺财"
dog.age = 3
print(dog.name)
print(dog.age)输出结果:
旺财
3这说明对象不只是一个空壳,它可以保存数据。
方法:对象“能做什么”
如果说属性表示“它有什么”,那么方法表示“它能做什么”。
例如:
- 狗可以叫
- 学生可以自我介绍
- 用户可以登录
方法本质上就是定义在类里面的函数。
class Dog:
def bark(self):
print("汪汪")
dog = Dog()
dog.bark()输出结果:
汪汪注意这里的方法和普通函数长得很像,但它定义在类内部,而且第一个参数写的是 self。
self 到底是什么
self 是初学面向对象时最容易卡住的地方。
你可以先这样理解:
self 表示“当前这个对象自己”。
看下面这个例子:
class Dog:
def bark(self):
print(self)
print("汪汪")
dog = Dog()
dog.bark()输出结果示例:
<__main__.Dog object at 0x000001>
汪汪当你写:
dog.bark()Python 会自动把 dog 这个对象本身传给 self。
所以:
dog.bark()不是“凭空调用一个函数”- 而是“让
dog这个对象调用它自己的方法”
为什么方法里必须写 self
因为对象方法往往要访问当前对象自己的属性。
例如:
class Dog:
def bark(self):
print(f"{self.name} 正在叫")
dog = Dog()
dog.name = "旺财"
dog.bark()输出结果:
旺财 正在叫如果没有 self,方法就不知道自己操作的是哪个对象。
__init__:初始化方法
前面我们是先创建对象,再手动给它加属性。这种写法在正式项目里不够规范。
更常见的做法是:对象一创建出来,就把基础属性准备好。
这就是 __init__ 的作用。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
dog = Dog("旺财", 3)
print(dog.name)
print(dog.age)输出结果:
旺财
3你可以把 __init__ 理解成“对象刚出生时要执行的初始化逻辑”。
拆解理解
dog = Dog("旺财", 3)这行代码做了两件事:
- 创建一个
Dog对象 - 自动调用
__init__,把"旺财"和3传进去
然后在 __init__ 里:
self.name = nameself.age = age
就把这两个数据保存到了对象自身身上。
一个更完整的面向对象例子
下面写一个“学生类”。
class Student:
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
def introduce(self):
print(f"大家好,我叫{self.name},今年{self.age}岁,来自{self.city}")
def study(self, subject):
print(f"{self.name} 正在学习 {subject}")
stu1 = Student("小明", 18, "上海")
stu2 = Student("小红", 19, "杭州")
stu1.introduce()
stu1.study("Python")
stu2.introduce()
stu2.study("Linux")输出结果:
大家好,我叫小明,今年18岁,来自上海
小明 正在学习 Python
大家好,我叫小红,今年19岁,来自杭州
小红 正在学习 Linux这个例子特别适合你理解面向对象的价值:
- 一个类可以创建多个对象
- 每个对象有自己的数据
- 但它们共享同一套行为模板
类变量和实例变量
这是初学者后面经常会碰到的一个点。
实例变量
写在 self.xxx 上的变量,通常是实例变量,也就是“每个对象各自拥有”的数据。
class Student:
def __init__(self, name):
self.name = name这里的 name 就是实例变量。
类变量
如果某个属性属于“整个类共享”,而不是每个对象单独一份,就可以写成类变量。
class Student:
school = "Python 学习空间"
def __init__(self, name):
self.name = name
stu1 = Student("小明")
stu2 = Student("小红")
print(stu1.school)
print(stu2.school)
print(Student.school)输出结果:
Python 学习空间
Python 学习空间
Python 学习空间这里的 school 就属于整个类共享。
__str__ 和 __repr__
当你直接打印一个对象时,默认显示的是类似这样的内容:
<__main__.Student object at 0x000001>这对人类不友好。
你可以通过 __str__ 或 __repr__ 自定义对象显示方式。
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"Student(name={self.name}, age={self.age})"
stu = Student("小明", 18)
print(stu)输出结果:
Student(name=小明, age=18)你可以先简单记住:
__str__更偏向给用户看__repr__更偏向给开发者调试看
零基础阶段先会用 __str__ 就够了。
继承:复用已有类的能力
当多个类有共同特征时,你不想每次都从头写一遍,这时就会用到继承。
例如:
- 狗和猫都是动物
- 学生和老师都是人
我们可以先写一个父类:
class Animal:
def eat(self):
print("正在吃东西")
def sleep(self):
print("正在睡觉")然后让 Dog 继承它:
class Animal:
def eat(self):
print("正在吃东西")
def sleep(self):
print("正在睡觉")
class Dog(Animal):
def bark(self):
print("汪汪")
dog = Dog()
dog.eat()
dog.sleep()
dog.bark()输出结果:
正在吃东西
正在睡觉
汪汪这里你可以看到:
Dog自己写了bark()- 但它也能直接使用从
Animal继承来的eat()和sleep()
这就是继承的意义:复用已有能力。
方法重写
如果子类不想完全沿用父类的方法,可以自己重写。
class Animal:
def speak(self):
print("动物发声")
class Dog(Animal):
def speak(self):
print("汪汪")
class Cat(Animal):
def speak(self):
print("喵喵")
dog = Dog()
cat = Cat()
dog.speak()
cat.speak()输出结果:
汪汪
喵喵这说明虽然它们都继承自 Animal,但可以根据自己的特点提供不同实现。
面向对象在真实项目里会出现在哪
如果你现在还觉得抽象,可以先看几个真实开发场景。
1. Django 模型
你后面学 Django 时,会写这样的代码:
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()这本质上就是面向对象。
2. 爬虫项目
你后面会写 Spider 类、中间件类、管道类,这些也都是面向对象。
3. 自己的业务对象
例如:
- 用户对象
- 商品对象
- 订单对象
- 课程对象
这些都天然适合用类来组织。
常见错误
1. 把类和对象混为一谈
要记住:
- 类是模板
- 对象是实例
2. 忘记写 self
下面这种写法会报错:
class Dog:
def bark():
print("汪汪")对象方法默认要接收当前对象,所以通常必须写 self。
3. 在方法里直接用变量名,不加 self
例如:
class Dog:
def __init__(self, name):
self.name = name
def bark(self):
print(name)这里的 name 没有定义,应该写成 self.name。
4. 一上来就钻牛角尖
零基础阶段不要一开始就纠结:
- 多重继承
- 魔术方法大全
- 设计模式
先把类、对象、属性、方法、继承这些基础真正吃透。
练习题
练习 1
定义一个 Book 类,包含:
- 书名
- 作者
- 价格
并写一个 show_info() 方法,用于打印图书信息。
练习 2
定义一个 User 类,包含:
- 用户名
- 年龄
并写一个 login() 方法,输出“某某正在登录”。
练习 3
定义一个父类 Person,再定义子类 Student 和 Teacher,让它们都继承 Person,并分别重写 introduce() 方法。
练习 4
给你写过的 Student 类加一个 __str__ 方法,让对象打印出来时更清晰。
本节小结
面向对象并不是为了让代码显得高级,而是为了让代码更有结构、更容易扩展。
你这一节最重要的收获应该是:
- 知道类和对象是什么
- 知道属性和方法分别代表什么
- 理解
self的意义 - 会用
__init__初始化对象 - 知道继承和重写是在解决什么问题
只要这些核心点清楚,后面你再学 Django、Scrapy、数据库模型时,就不会觉得它们像“另一个世界”的东西。因为本质上,它们都建立在面向对象这套思维之上。