Skip to content

面向对象

很多初学者第一次看到“面向对象”这四个字,就会紧张,觉得这一定是很高级、很抽象、很难的内容。

实际上,面向对象最核心的目标只有一个:让代码更容易组织。

当你的程序很小时,只写几个函数就够了;但当程序里开始出现“学生”“用户”“商品”“订单”“文章”“爬虫任务”这类带有数据和行为的对象时,只用函数就会越来越乱。这个时候,面向对象就开始有价值了。

所以你不要把这一节理解成“高深理论”,而是把它理解成:一种更适合组织复杂程序的写法。

本节目标

  • 理解什么是类和对象
  • 理解属性和方法
  • 学会使用 __init__
  • 理解 self 的作用
  • 学会创建对象并调用方法
  • 理解继承和方法重写
  • 建立对面向对象的基本直觉

先修知识

在学习这一节之前,你至少应该已经掌握:

  • 变量
  • 函数
  • 列表和字典
  • 条件语句和循环

因为面向对象不是独立于这些基础语法存在的,它只是把这些能力组织得更有结构。

为什么会有面向对象

先看一个没有使用面向对象的例子。

python
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)

输出结果:

text
小明 正在学习
大家好,我叫小明,今年18岁,来自上海

这段代码在数据很少时没有问题。但如果学生变成 100 个,你就会发现:

  • 变量越来越多
  • 相关函数越来越散
  • 数据和行为没有被组织在一起

这个时候,我们就希望把“学生的属性”和“学生的行为”放在一起管理。这就是面向对象的出发点。

类和对象到底是什么

你可以先用一个非常直观的比喻理解:

  • 类:设计图
  • 对象:根据设计图造出来的具体实例

例如:

  • “狗”这个概念可以看成类
  • 你家里的那只名叫“旺财”的狗,就是对象

再比如:

  • “学生”这个抽象概念是类
  • “小明”“小红”这些具体学生是对象

第一个类

python
class Dog:
    pass

这里定义了一个叫 Dog 的类。

你可以暂时把 class 理解成“创建一个新模板”的关键字。

pass 的意思是“先占个位置,什么都不做”。

创建对象

类定义好以后,就可以根据这个类创建对象。

python
class Dog:
    pass


dog1 = Dog()
dog2 = Dog()

print(dog1)
print(dog2)

输出结果示例:

text
<__main__.Dog object at 0x000001>
<__main__.Dog object at 0x000002>

虽然看起来内容有点奇怪,但你至少可以先知道一件事:dog1dog2 是两个不同的对象。

属性:对象“有什么”

属性就是对象身上的数据。

比如一只狗,可能有这些属性:

  • 名字
  • 年龄
  • 颜色

我们可以在对象创建后临时给它加属性:

python
class Dog:
    pass


dog = Dog()
dog.name = "旺财"
dog.age = 3

print(dog.name)
print(dog.age)

输出结果:

text
旺财
3

这说明对象不只是一个空壳,它可以保存数据。

方法:对象“能做什么”

如果说属性表示“它有什么”,那么方法表示“它能做什么”。

例如:

  • 狗可以叫
  • 学生可以自我介绍
  • 用户可以登录

方法本质上就是定义在类里面的函数。

python
class Dog:
    def bark(self):
        print("汪汪")


dog = Dog()
dog.bark()

输出结果:

text
汪汪

注意这里的方法和普通函数长得很像,但它定义在类内部,而且第一个参数写的是 self

self 到底是什么

self 是初学面向对象时最容易卡住的地方。

你可以先这样理解:

self 表示“当前这个对象自己”。

看下面这个例子:

python
class Dog:
    def bark(self):
        print(self)
        print("汪汪")


dog = Dog()
dog.bark()

输出结果示例:

text
<__main__.Dog object at 0x000001>
汪汪

当你写:

python
dog.bark()

Python 会自动把 dog 这个对象本身传给 self

所以:

  • dog.bark() 不是“凭空调用一个函数”
  • 而是“让 dog 这个对象调用它自己的方法”

为什么方法里必须写 self

因为对象方法往往要访问当前对象自己的属性。

例如:

python
class Dog:
    def bark(self):
        print(f"{self.name} 正在叫")


dog = Dog()
dog.name = "旺财"
dog.bark()

输出结果:

text
旺财 正在叫

如果没有 self,方法就不知道自己操作的是哪个对象。

__init__:初始化方法

前面我们是先创建对象,再手动给它加属性。这种写法在正式项目里不够规范。

更常见的做法是:对象一创建出来,就把基础属性准备好。

这就是 __init__ 的作用。

python
class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age


dog = Dog("旺财", 3)
print(dog.name)
print(dog.age)

输出结果:

text
旺财
3

你可以把 __init__ 理解成“对象刚出生时要执行的初始化逻辑”。

拆解理解

python
dog = Dog("旺财", 3)

这行代码做了两件事:

  1. 创建一个 Dog 对象
  2. 自动调用 __init__,把 "旺财"3 传进去

然后在 __init__ 里:

  • self.name = name
  • self.age = age

就把这两个数据保存到了对象自身身上。

一个更完整的面向对象例子

下面写一个“学生类”。

python
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")

输出结果:

text
大家好,我叫小明,今年18岁,来自上海
小明 正在学习 Python
大家好,我叫小红,今年19岁,来自杭州
小红 正在学习 Linux

这个例子特别适合你理解面向对象的价值:

  • 一个类可以创建多个对象
  • 每个对象有自己的数据
  • 但它们共享同一套行为模板

类变量和实例变量

这是初学者后面经常会碰到的一个点。

实例变量

写在 self.xxx 上的变量,通常是实例变量,也就是“每个对象各自拥有”的数据。

python
class Student:
    def __init__(self, name):
        self.name = name

这里的 name 就是实例变量。

类变量

如果某个属性属于“整个类共享”,而不是每个对象单独一份,就可以写成类变量。

python
class Student:
    school = "Python 学习空间"

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


stu1 = Student("小明")
stu2 = Student("小红")

print(stu1.school)
print(stu2.school)
print(Student.school)

输出结果:

text
Python 学习空间
Python 学习空间
Python 学习空间

这里的 school 就属于整个类共享。

__str____repr__

当你直接打印一个对象时,默认显示的是类似这样的内容:

text
<__main__.Student object at 0x000001>

这对人类不友好。

你可以通过 __str____repr__ 自定义对象显示方式。

python
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)

输出结果:

text
Student(name=小明, age=18)

你可以先简单记住:

  • __str__ 更偏向给用户看
  • __repr__ 更偏向给开发者调试看

零基础阶段先会用 __str__ 就够了。

继承:复用已有类的能力

当多个类有共同特征时,你不想每次都从头写一遍,这时就会用到继承。

例如:

  • 狗和猫都是动物
  • 学生和老师都是人

我们可以先写一个父类:

python
class Animal:
    def eat(self):
        print("正在吃东西")

    def sleep(self):
        print("正在睡觉")

然后让 Dog 继承它:

python
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()

输出结果:

text
正在吃东西
正在睡觉
汪汪

这里你可以看到:

  • Dog 自己写了 bark()
  • 但它也能直接使用从 Animal 继承来的 eat()sleep()

这就是继承的意义:复用已有能力。

方法重写

如果子类不想完全沿用父类的方法,可以自己重写。

python
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()

输出结果:

text
汪汪
喵喵

这说明虽然它们都继承自 Animal,但可以根据自己的特点提供不同实现。

面向对象在真实项目里会出现在哪

如果你现在还觉得抽象,可以先看几个真实开发场景。

1. Django 模型

你后面学 Django 时,会写这样的代码:

python
class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()

这本质上就是面向对象。

2. 爬虫项目

你后面会写 Spider 类、中间件类、管道类,这些也都是面向对象。

3. 自己的业务对象

例如:

  • 用户对象
  • 商品对象
  • 订单对象
  • 课程对象

这些都天然适合用类来组织。

常见错误

1. 把类和对象混为一谈

要记住:

  • 类是模板
  • 对象是实例

2. 忘记写 self

下面这种写法会报错:

python
class Dog:
    def bark():
        print("汪汪")

对象方法默认要接收当前对象,所以通常必须写 self

3. 在方法里直接用变量名,不加 self

例如:

python
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,再定义子类 StudentTeacher,让它们都继承 Person,并分别重写 introduce() 方法。

练习 4

给你写过的 Student 类加一个 __str__ 方法,让对象打印出来时更清晰。

本节小结

面向对象并不是为了让代码显得高级,而是为了让代码更有结构、更容易扩展。

你这一节最重要的收获应该是:

  • 知道类和对象是什么
  • 知道属性和方法分别代表什么
  • 理解 self 的意义
  • 会用 __init__ 初始化对象
  • 知道继承和重写是在解决什么问题

只要这些核心点清楚,后面你再学 Django、Scrapy、数据库模型时,就不会觉得它们像“另一个世界”的东西。因为本质上,它们都建立在面向对象这套思维之上。

Built with VitePress.