面向对象概述
面向对象编程是一种以"对象"为核心来组织代码的编程思想,将数据和操作数据的方法封装在一起
在之前的学习中,我们主要通过函数来组织代码——把数据传入函数,函数处理后返回结果。这是面向过程编程。
而面向对象编程的核心思路是:将现实世界中的事物抽象为对象,每个对象有自己的属性(数据)和方法(行为)。
面向过程 vs 面向对象:
面向过程:关注"怎么做"——步骤1→步骤2→步骤3,按流程执行
面向对象:关注"谁来做"——找到负责的对象,让它调用方法来完成
一个简单的对比:
1 2 3 4 5 6 7 8 9 10
| stu_name = "小明" stu_age = 18 stu_scores = [85, 92, 78]
def get_average(scores): return sum(scores) / len(scores)
print(f"{stu_name},{stu_age}岁,平均分{get_average(stu_scores)}")
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Student: def __init__(self, name, age, scores): self.name = name self.age = age self.scores = scores def get_average(self): return sum(self.scores) / len(self.scores)
stu = Student("小明", 18, [85, 92, 78]) print(f"{stu.name},{stu.age}岁,平均分{stu.get_average()}")
|
面向对象的三大特性:
封装 — 将数据和操作封装在类内部,隐藏实现细节
继承 — 子类复用父类的属性和方法,实现代码复用
多态 — 同一操作作用于不同对象,可以有不同的行为
类与对象
类是对象的模板/蓝图,对象是类的具体实例。通过 class 关键字定义类,通过 类名() 创建对象
- 类的定义与对象的创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| """ class 类名: 类的属性和方法定义
对象名 = 类名() 创建该类的实例 """
class Dog: """狗类""" species = "犬科" def bark(self): print("汪汪!")
dog1 = Dog() dog2 = Dog()
print(dog1.species) dog1.bark() print(dog2.species)
|
1 2 3 4
| print(dog1) print(dog2) print(dog1 is dog2)
|
- 实例属性与 self
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| """ self 代表当前对象本身,是方法中访问对象属性的桥梁 在定义方法时,self 必须作为第一个参数 在调用方法时,Python 会自动将调用者传给 self,不需要手动传 """
class Dog: def set_info(self, name, age): """给当前对象设置属性""" self.name = name self.age = age def introduce(self): print(f"我叫{self.name},今年{self.age}岁")
dog = Dog() dog.set_info("旺财", 3) dog.introduce()
|
构造方法 init
init 是类的构造方法,在创建对象时自动调用,用于初始化对象的属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| """ __init__(self, ...) 构造方法: - 在 类名() 创建对象时自动执行 - 用于设置对象的初始状态(属性) - self 参数必须有,后面可以跟其他参数 """
class Student: def __init__(self, name, age, grade): """创建学生对象时自动调用,初始化属性""" self.name = name self.age = age self.grade = grade print(f"学生 {self.name} 已创建") def show_info(self): print(f"姓名:{self.name},年龄:{self.age},年级:{self.grade}")
stu1 = Student("小明", 18, "高三") stu2 = Student("小红", 17, "高二")
stu1.show_info() stu2.show_info()
|
1 2 3 4 5 6 7 8 9 10 11 12
| class Book: def __init__(self, title, author="佚名", pages=0): self.title = title self.author = author self.pages = pages
book1 = Book("Python入门", "张三", 300) book2 = Book("日记本")
print(book2.author) print(book2.pages)
|
成员方法与属性
类内部定义的函数称为方法,通过 self 绑定的变量称为实例属性
- 实例方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| """ 实例方法:第一个参数是 self,通过对象来调用 实例方法可以访问和修改对象的属性 """
class BankAccount: def __init__(self, owner, balance=0): self.owner = owner self.balance = balance def deposit(self, amount): if amount > 0: self.balance += amount print(f"存入 {amount} 元,余额:{self.balance} 元") def withdraw(self, amount): if amount > self.balance: print(f"余额不足(余额:{self.balance} 元)") elif amount > 0: self.balance -= amount print(f"取出 {amount} 元,余额:{self.balance} 元") def show_balance(self): print(f"{self.owner} 的余额:{self.balance} 元")
acc = BankAccount("PyTs1n9", 1000) acc.deposit(500) acc.withdraw(200) acc.show_balance()
|
- str 方法(魔术方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| """ __str__(self) 方法: 定义对象被 print() 或 str() 时的字符串表示 不定义时默认输出 <__main__.类名 object at 0x...> """
class Student: def __init__(self, name, age): self.name = name self.age = age def __str__(self): """定义对象的字符串表示""" return f"Student({self.name}, {self.age}岁)"
stu = Student("小明", 18) print(stu)
|
- 类属性 vs 实例属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| """ 类属性:定义在类内部、方法外部的变量,所有实例共享 实例属性:通过 self.xxx 在方法内部定义的变量,每个实例独有 """
class Student: school = "第一中学" def __init__(self, name): self.name = name
stu1 = Student("小明") stu2 = Student("小红")
print(stu1.school) print(stu2.school) print(stu1.name) print(stu2.name)
Student.school = "第二中学" print(stu1.school) print(stu2.school)
|
封装
将属性和方法"包装"在类内部,通过访问控制隐藏内部实现,只暴露必要的接口
- 私有属性与方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| """ Python 中通过命名约定来实现封装: - _name:单下划线开头,表示"约定受保护"(仍可从外部访问,但不建议) - __name:双下划线开头,触发名称改写(name mangling),更难从外部访问 - __name__:双下划线开头结尾,是系统定义的魔术方法,一般不自己定义这种 """
class Student: def __init__(self, name, age): self.name = name self._age = age self.__score = 0 def set_score(self, score): """通过公开方法设置私有属性(可以加校验逻辑)""" if 0 <= score <= 100: self.__score = score else: print("分数必须在 0-100 之间") def get_score(self): """通过公开方法获取私有属性""" return self.__score def __private_method(self): """私有方法,只能在类内部调用""" print("这是私有方法")
stu = Student("小明", 18) print(stu.name) print(stu._age)
stu.set_score(95) print(stu.get_score())
|
1 2 3 4 5 6 7 8 9 10
| """ __score 实际上被改名为 _Student__score Python 并没有真正的"私有",只是改了名字防止意外访问 """ stu = Student("小明", 18) stu.set_score(88)
print(stu._Student__score)
|
- property 装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| """ @property 装饰器将方法调用变成属性访问的形式 既保留了封装(内部可以加逻辑),又让调用更简洁 """
class Circle: def __init__(self, radius): self._radius = radius @property def radius(self): """获取半径""" return self._radius @radius.setter def radius(self, value): """设置半径(带校验)""" if value <= 0: raise ValueError("半径必须大于 0") self._radius = value @property def area(self): """面积(只读属性,不需要 setter)""" import math return math.pi * self._radius ** 2
c = Circle(5) print(c.radius) c.radius = 10 print(c.area)
|
继承
子类继承父类的属性和方法,实现代码复用;可以重写父类方法来定制行为
- 单继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| """ class 子类名(父类名): pass
子类自动获得父类的所有属性和方法 """
class Animal: def __init__(self, name): self.name = name def eat(self): print(f"{self.name} 在吃东西") def sleep(self): print(f"{self.name} 在睡觉")
class Dog(Animal): def bark(self): print(f"{self.name} 汪汪叫")
class Cat(Animal): def meow(self): print(f"{self.name} 喵喵叫")
dog = Dog("旺财") dog.eat() dog.sleep() dog.bark()
cat = Cat("咪咪") cat.meow()
|
- 方法重写(Override)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| """ 子类定义与父类同名的方法,覆盖父类的实现 通过 super() 可以在重写的方法中调用父类的方法 """
class Animal: def __init__(self, name): self.name = name def speak(self): print(f"{self.name} 发出声音")
class Dog(Animal): def speak(self): """重写父类的 speak 方法""" print(f"{self.name} 汪汪叫")
class Cat(Animal): def speak(self): print(f"{self.name} 喵喵叫")
dog = Dog("旺财") cat = Cat("咪咪") dog.speak() cat.speak()
|
- super() 调用父类方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| """ super() 返回父类的临时对象,用于调用父类方法 在重写方法时经常需要先调用父类的同名方法,再添加子类的逻辑 """
class Animal: def __init__(self, name, age): self.name = name self.age = age print(f"Animal init:{self.name}")
class Dog(Animal): def __init__(self, name, age, breed): super().__init__(name, age) self.breed = breed print(f"Dog init:{self.name},品种{self.breed}")
dog = Dog("旺财", 3, "金毛")
print(dog.breed)
|
1 2 3 4 5
| class DogWithoutSuper(Animal): def __init__(self, name, age, breed): Animal.__init__(self, name, age) self.breed = breed
|
- 多重继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| """ class 子类(父类1, 父类2, ...): 子类可以继承多个父类 属性/方法的查找顺序遵循 MRO(Method Resolution Order) 使用 类名.__mro__ 或 类名.mro() 查看解析顺序 """
class Flyer: def fly(self): print("可以飞")
class Swimmer: def swim(self): print("可以游泳")
class Duck(Flyer, Swimmer): def quack(self): print("嘎嘎叫")
duck = Duck() duck.fly() duck.swim() duck.quack()
print(Duck.__mro__)
|
多态
多态是指同一操作作用于不同对象时,可以产生不同的行为;在 Python 中是天然支持的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| """ 多态的核心:不同的对象拥有同名方法,调用时不需要关心对象具体是什么类型 Python 的鸭子类型:"如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子" """
class Dog: def speak(self): return "汪汪"
class Cat: def speak(self): return "喵喵"
class Duck: def speak(self): return "嘎嘎"
def animal_sound(animal): """任何有 speak 方法的对象都可以传入""" print(animal.speak())
animal_sound(Dog()) animal_sound(Cat()) animal_sound(Duck())
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class Circle: def __init__(self, radius): self.radius = radius def area(self): import math return math.pi * self.radius ** 2
class Rectangle: def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height
class Triangle: def __init__(self, base, height): self.base = base self.height = height def area(self): return 0.5 * self.base * self.height
shapes = [ Circle(5), Rectangle(4, 6), Triangle(3, 8) ]
total_area = sum(shape.area() for shape in shapes) print(f"总面积:{total_area:.2f}")
|
类方法与静态方法
类方法用 @classmethod 装饰,操作类本身;静态方法用 @staticmethod 装饰,逻辑上属于类但不操作实例或类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Student: count = 0 def __init__(self, name): self.name = name Student.count += 1 def introduce(self): """实例方法:操作实例属性""" print(f"我叫{self.name}") @classmethod def get_count(cls): """类方法:操作类属性,第一个参数是类本身(cls)""" return cls.count @classmethod def create_anonymous(cls): """类方法:作为工厂方法创建实例""" return cls("无名") @staticmethod def is_valid_name(name): """静态方法:不需要访问实例或类,只是逻辑上相关""" return len(name) >= 2 and not name.isspace()
stu = Student("小明") stu.introduce()
print(Student.get_count()) stu2 = Student.create_anonymous() print(stu2.name)
print(Student.is_valid_name("王")) print(Student.is_valid_name("王小"))
|
1 2 3 4 5 6 7 8 9 10
| """ ┌──────────────┬─────────────┬──────────────┬──────────────────┐ │ 类型 │ 装饰器 │ 第一个参数 │ 主要用途 │ ├──────────────┼─────────────┼──────────────┼──────────────────┤ │ 实例方法 │ 不需要 │ self(实例) │ 操作实例属性 │ │ 类方法 │ @classmethod │ cls(类) │ 操作类属性/工厂方法 │ │ 静态方法 │@staticmethod │ 无 │ 工具函数/逻辑归组 │ └──────────────┴─────────────┴──────────────┴──────────────────┘ """
|
魔术方法
魔术方法(Magic Method)是 Python 中以双下划线开头和结尾的特殊方法,可以自定义对象的行为
常用的魔术方法:
__init__(self, ...) 构造方法,创建对象时调用
__str__(self) print() / str() 时调用,返回用户友好的字符串
__repr__(self) repr() / 调试时调用,返回开发者友好的字符串
__len__(self) len() 时调用
__eq__(self, other) 使用 == 比较时调用
__lt__(self, other) 使用 < 比较时调用
__add__(self, other) 使用 + 运算时调用
__getitem__(self, key) 使用 obj[key] 索引时调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class Book: def __init__(self, title, author, pages): self.title = title self.author = author self.pages = pages def __str__(self): """用户友好的字符串表示""" return f"《{self.title}》— {self.author}" def __repr__(self): """开发者友好的字符串表示""" return f"Book('{self.title}', '{self.author}', {self.pages})" def __len__(self): """len() 返回页数""" return self.pages def __eq__(self, other): """== 判断是否是同一本书(同书名和同作者)""" if isinstance(other, Book): return self.title == other.title and self.author == other.author return False
book1 = Book("Python入门", "张三", 300) book2 = Book("Python入门", "张三", 500)
print(str(book1)) print(repr(book1)) print(len(book1)) print(book1 == book2)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): """定义 + 运算:向量加法""" return Vector(self.x + other.x, self.y + other.y) def __mul__(self, scalar): """定义 * 运算:向量数乘""" return Vector(self.x * scalar, self.y * scalar) def __str__(self): return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2) v2 = Vector(3, 4) print(v1 + v2) print(v1 * 3)
|
综合练习
将面向对象知识融会贯通,通过实际案例巩固类与对象、封装、继承、多态的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| """ 练习一:图书管理系统 演示:封装、继承、多态 """
class LibraryItem: """图书馆通用物品(父类)""" def __init__(self, title, item_id): self.title = title self.item_id = item_id self.__is_borrowed = False def borrow(self): if self.__is_borrowed: print(f"「{self.title}」已被借出") return False self.__is_borrowed = True print(f"「{self.title}」借出成功") return True def return_item(self): if not self.__is_borrowed: print(f"「{self.title}」未被借出") return False self.__is_borrowed = False print(f"「{self.title}」归还成功") return True def is_borrowed(self): return self.__is_borrowed def get_info(self): status = "已借出" if self.__is_borrowed else "可借" return f"[{self.item_id}] {self.title} — {status}"
class Book(LibraryItem): """书籍(子类)""" def __init__(self, title, item_id, author, pages): super().__init__(title, item_id) self.author = author self.pages = pages def get_info(self): """重写父类方法,添加书籍特有信息""" base_info = super().get_info() return f"{base_info} | 作者:{self.author} | {self.pages}页"
class DVD(LibraryItem): """DVD(子类)""" def __init__(self, title, item_id, duration): super().__init__(title, item_id) self.duration = duration def get_info(self): base_info = super().get_info() return f"{base_info} | 时长:{self.duration}分钟"
items = [ Book("Python编程", "B001", "张三", 450), Book("数据结构", "B002", "李四", 320), DVD("Python教程", "D001", 120) ]
for item in items: print(item.get_info())
items[0].borrow() items[0].borrow() items[0].return_item()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| """ 练习二:猜拳游戏(面向对象版) 演示:封装,类的交互 """ import random
class Player: def __init__(self, name): self.name = name self.score = 0 def choose(self): """玩家出拳""" choices = {1: "石头", 2: "剪刀", 3: "布"} while True: try: choice = int(input(f"{self.name},请出拳(1石头 2剪刀 3布):")) if choice in choices: return choice print("请输入 1、2 或 3") except ValueError: print("请输入有效数字")
class Computer: def __init__(self): self.name = "电脑" self.score = 0 def choose(self): """电脑随机出拳""" return random.randint(1, 3)
class Game: """游戏主逻辑""" CHOICES = {1: "石头", 2: "剪刀", 3: "布"} def __init__(self): self.player = Player("玩家") self.computer = Computer() def judge(self, p_choice, c_choice): """判断胜负,返回 1=玩家赢 -1=电脑赢 0=平局""" diff = p_choice - c_choice if diff == 0: return 0 return 1 if diff in (-1, 2) else -1 def play_round(self): p = self.player.choose() c = self.computer.choose() print(f"{self.computer.name}出了:{self.CHOICES[c]}") result = self.judge(p, c) if result == 1: self.player.score += 1 print(f"{self.player.name} 赢!") elif result == -1: self.computer.score += 1 print(f"{self.computer.name} 赢!") else: print("平局!") print(f"比分 — {self.player.name}:{self.player.score} \ {self.computer.name}:{self.computer.score}")
|
面向对象是 Python 编程的分水岭。掌握类与对象的创建、理解封装/继承/多态三大特性、善用魔术方法和 property 装饰器,你就能以更符合人类思维方式来组织代码。记住:类是模板,对象是实例;self 指向当前对象;super() 连接父子类;多态让代码更灵活。面向对象不是银弹,但在构建大型项目时,它是不可或缺的组织工具。
Python Study Note 系列文章
- Python Study Note
- Python 函数使用(四)
- Python 判断语句(二)
- Python 基础语法(一)
- Python 异常处理(七)
- Python 循环语句(三)
- Python 数据容器(五)
- Python 文件基础操作(六)
- Python 模块与包(八)
- Python 类型注解(十)
- Python 面向对象(九)重点
- Python 高阶技巧(十一)