30天入门Python(基础篇)------第27天:Python面向对象详解
📅 学习日期 :第27天 | ⏱️ 预计用时 :60分钟 | 📊 难度等级:⭐⭐⭐
🎯 学习目标
- 理解面向对象编程的核心概念
- 掌握类和对象的定义方法
- 学会使用
__init__构造方法 - 理解实例属性、实例方法、类属性、类方法的区别
- 掌握
self的作用和使用 - 了解面向对象的三大特征:封装、继承、多态
一、什么是面向对象编程?
1.1 编程范式对比
面向过程编程:按照步骤一步步执行,关注"怎么做"。
python
# 面向过程:步骤化
name = "小明"
age = 20
print(f"姓名: {name}, 年龄: {age}")
面向对象编程:将数据和操作封装成对象,关注"谁来做"。
python
# 面向对象:对象化
student = Student("小明", 20)
student.introduce()
1.2 核心概念
| 概念 | 说明 | 生活类比 |
|---|---|---|
| 类(Class) | 对象的模板/蓝图 | 汽车设计图 |
| 对象(Object) | 类的具体实例 | 根据设计图制造的汽车 |
| 属性(Attribute) | 对象的特征数据 | 汽车的颜色、品牌 |
| 方法(Method) | 对象能执行的行为 | 汽车启动、加速 |
二、创建第一个类
2.1 基本语法
python
class 类名:
"""类的文档字符串"""
def __init__(self, 参数1, 参数2, ...):
"""构造方法"""
self.属性1 = 参数1
self.属性2 = 参数2
def 方法名(self):
"""实例方法"""
...
2.2 实战示例:学生类
python
class Student:
"""学生类"""
def __init__(self, name, age, score):
"""初始化学生对象"""
self.name = name # 姓名
self.age = age # 年龄
self.score = score # 成绩
def introduce(self):
"""自我介绍"""
print(f"大家好,我是 {self.name},今年 {self.age} 岁。")
def get_grade(self):
"""获取成绩等级"""
if self.score >= 90:
return "优秀"
elif self.score >= 80:
return "良好"
elif self.score >= 60:
return "及格"
else:
return "不及格"
# 创建对象
stu1 = Student("小明", 20, 95)
stu2 = Student("小红", 21, 78)
# 调用方法
stu1.introduce() # 大家好,我是小明,今年20岁。
print(f"等级: {stu1.get_grade()}") # 等级: 优秀
stu2.introduce() # 大家好,我是小红,今年21岁。
print(f"等级: {stu2.get_grade()}") # 等级: 及格
2.3 理解 self
self 是 Python 面向对象中的关键字参数,代表对象自身。
python
class Cat:
def __init__(self, name):
self.name = name # self.name 是实例属性
# name 是局部参数
def meow(self):
# self 指向调用该方法的对象
print(f"{self.name} 说: 喵~")
# 创建对象
cat = Cat("咪咪")
# 等价于: Cat.__init__(cat, "咪咪")
# 调用方法
cat.meow()
# 等价于: Cat.meow(cat)
self 的要点:
self不是关键字,只是一个约定(可以改成其他名字,但强烈建议不要改)self是方法的第一个参数,指向调用该方法的对象- 调用方法时,Python 自动传入
self,不需要手动传 - 在
__init__中,self.属性 = 值就是创建实例属性
三、类的组成
3.1 构造方法 __init__
python
class Person:
def __init__(self, name, age=18):
self.name = name
self.age = age
print(f"创建了 {self.name},年龄 {self.age}")
# 使用
p1 = Person("张三") # age 使用默认值 18
p2 = Person("李四", 25) # 指定 age
特点:
__init__是特殊方法(魔术方法),在创建对象时自动调用- 可以有默认参数
- 不能有返回值(隐式返回
None)
3.2 实例方法
python
class Calculator:
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b
calc = Calculator()
print(calc.add(3, 5)) # 8
print(calc.subtract(10, 4)) # 6
3.3 查看对象属性
python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p = Person("小明", 20)
# 方式一:直接访问
print(p.name) # 小明
print(p.age) # 20
# 方式二:通过字典
print(p.__dict__) # {'name': '小明', 'age': 20}
# 方式三:动态获取属性
print(getattr(p, "name")) # 小明
print(getattr(p, "age")) # 20
print(hasattr(p, "name")) # True
print(hasattr(p, "email")) # False
# 方式四:设置属性
setattr(p, "email", "test@example.com")
print(p.email) # test@example.com
3.4 动态添加属性
python
class Student:
def __init__(self, name):
self.name = name
stu = Student("小明")
# 动态添加属性(不推荐,应在 __init__ 中定义)
stu.age = 20
stu.email = "xiaoming@example.com"
print(stu.name) # 小明
print(stu.age) # 20
print(stu.email) # xiaoming@example.com
四、属性的封装
4.1 私有属性
python
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner # 公开属性
self.__balance = balance # 私有属性(双下划线前缀)
def deposit(self, amount):
"""存款"""
if amount > 0:
self.__balance += amount
print(f"存款 {amount},余额: {self.__balance}")
else:
print("金额必须为正数")
def withdraw(self, amount):
"""取款"""
if amount <= self.__balance:
self.__balance -= amount
print(f"取款 {amount},余额: {self.__balance}")
else:
print("余额不足")
def get_balance(self):
"""查询余额(公开接口)"""
return self.__balance
# 使用
account = BankAccount("张三", 1000)
account.deposit(500) # 存款 500,余额: 1500
account.withdraw(200) # 取款 200,余额: 1300
# 不能直接访问私有属性
# print(account.__balance) # AttributeError
# 可以通过公开方法访问
print(f"当前余额: {account.get_balance()}") # 1300
4.2 私有属性的本质
python
class MyClass:
def __init__(self):
self.__secret = "hidden"
obj = MyClass()
# Python 实际上是将 __secret 改名为 _类名__secret
print(obj._MyClass__secret) # hidden(可以访问,但不推荐)
命名约定:
_name:受保护的属性(约定不要直接访问,但可以访问)__name:私有属性(会被名称改写,外部难以直接访问)
五、@property 装饰器
5.1 属性访问控制
python
class Student:
def __init__(self, name, score):
self.name = name
self.score = score # 可以被任意修改
stu = Student("小明", 95)
stu.score = 150 # 不合理,但没有阻止
使用 @property 可以实现属性的读写控制:
python
class Student:
def __init__(self, name, score):
self.name = name
self._score = score # 使用受保护的属性
@property
def score(self):
"""获取成绩(getter)"""
return self._score
@score.setter
def score(self, value):
"""设置成绩(setter),带验证"""
if not 0 <= value <= 100:
raise ValueError("成绩必须在 0-100 之间")
self._score = value
@score.deleter
def score(self):
"""删除成绩"""
print(f"删除了 {self.name} 的成绩")
del self._score
# 使用
stu = Student("小明", 95)
print(stu.score) # 95(自动调用 getter)
stu.score = 88 # 自动调用 setter
print(stu.score) # 88
stu.score = 150 # ValueError: 成绩必须在 0-100 之间
5.2 @property 的常见用法
python
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
"""只读属性:计算面积"""
return self.width * self.height
@property
def perimeter(self):
"""只读属性:计算周长"""
return 2 * (self.width + self.height)
rect = Rectangle(5, 3)
print(f"面积: {rect.area}") # 15
print(f"周长: {rect.perimeter}") # 16
六、魔法方法(特殊方法)
6.1 __str__ 和 __repr__
python
class Student:
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
def __str__(self):
"""用户友好字符串,用于 print()"""
return f"Student({self.name}, {self.age}岁, {self.score}分)"
def __repr__(self):
"""开发者友好字符串,用于调试"""
return f"Student(name='{self.name}', age={self.age}, score={self.score})"
stu = Student("小明", 20, 95)
print(stu) # Student(小明, 20岁, 95分)
repr(stu) # Student(name='小明', age=20, score=95)
区别:
__str__:面向用户,print()和str()调用__repr__:面向开发者,repr()和交互式解释器调用- 如果只定义一个,优先定义
__repr__
6.2 常用魔法方法一览
python
class MyClass:
def __init__(self, value):
self.value = value
def __str__(self): # str(obj), print(obj)
return f"值为 {self.value}"
def __repr__(self): # repr(obj)
return f"MyClass({self.value})"
def __len__(self): # len(obj)
return self.value
def __add__(self, other): # obj1 + obj2
return MyClass(self.value + other.value)
def __eq__(self, other): # obj1 == obj2
return self.value == other.value
def __lt__(self, other): # obj1 < obj2
return self.value < other.value
def __getitem__(self, key): # obj[key]
return self.value[key]
def __len__(self): # len(obj)
return len(self.value)
def __del__(self): # del obj / 对象销毁时
print(f"对象 {self} 被销毁")
6.3 自定义容器类
python
class StudentList:
"""自定义学生列表"""
def __init__(self):
self._students = []
def add(self, student):
self._students.append(student)
def __len__(self):
return len(self._students)
def __getitem__(self, index):
return self._students[index]
def __contains__(self, student):
return student in self._students
def __str__(self):
return "\n".join(str(s) for s in self._students)
# 使用
students = StudentList()
students.add(Student("张三", 20, 95))
students.add(Student("李四", 21, 88))
print(len(students)) # 2
print(students[0]) # Student(张三, 20岁, 95分)
print(Student("张三", 20, 95) in students) # True
print(students) # 全部打印
七、类的继承与多态
7.1 继承基础(详细见第28天)
python
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "..."
class Dog(Animal):
def speak(self):
return f"{self.name} 说: 汪汪!"
class Cat(Animal):
def speak(self):
return f"{self.name} 说: 喵喵!"
# 多态
animals = [Dog("旺财"), Cat("咪咪"), Dog("大黄")]
for animal in animals:
print(animal.speak())
7.2 super() 函数
python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
return f"我叫 {self.name},今年 {self.age} 岁。"
class Teacher(Person):
def __init__(self, name, age, subject):
super().__init__(name, age) # 调用父类构造
self.subject = subject
def introduce(self):
base = super().introduce() # 调用父类方法
return f"{base} 我教 {self.subject}。"
teacher = Teacher("王老师", 35, "数学")
print(teacher.introduce())
# 我叫王老师,今年 35 岁。我教数学。
八、类方法、静态方法
8.1 实例方法、类方法、静态方法对比
python
class MyClass:
class_attr = "类属性"
def __init__(self, value):
self.value = value
# 实例方法:需要 self,操作实例属性
def instance_method(self):
return f"实例方法: value = {self.value}"
# 类方法:使用 @classmethod,需要 cls
@classmethod
def class_method(cls):
return f"类方法: class_attr = {cls.class_attr}"
# 静态方法:使用 @staticmethod,不需要 self 或 cls
@staticmethod
def static_method(x, y):
return f"静态方法: {x} + {y} = {x + y}"
# 调用
obj = MyClass(42)
print(obj.instance_method()) # 实例方法: value = 42
print(obj.class_method()) # 类方法: class_attr = 类属性
print(obj.static_method(3, 5)) # 静态方法: 3 + 5 = 8
# 类方法可以直接通过类调用
print(MyClass.class_method()) # 类方法: class_attr = 类属性
print(MyClass.static_method(1, 2)) # 静态方法: 1 + 2 = 3
8.2 类方法的实用场景:工厂方法
python
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
def __str__(self):
return f"{self.year}-{self.month:02d}-{self.day:02d}"
@classmethod
def from_string(cls, date_str):
"""从字符串创建日期对象(工厂方法)"""
year, month, day = map(int, date_str.split("-"))
return cls(year, month, day)
@classmethod
def today(cls):
"""获取今天的日期(工厂方法)"""
from datetime import date
today = date.today()
return cls(today.year, today.month, today.day)
# 使用
d1 = Date(2026, 4, 28)
print(d1) # 2026-04-28
d2 = Date.from_string("2026-01-01")
print(d2) # 2026-01-01
d3 = Date.today()
print(d3) # 2026-04-28
九、实战项目:图书管理系统
python
class Book:
"""图书类"""
def __init__(self, title, author, isbn):
self.title = title
self.author = author
self.isbn = isbn
self._is_borrowed = False
@property
def is_borrowed(self):
return self._is_borrowed
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_book(self):
self._is_borrowed = False
print(f"归还《{self.title}》")
def __str__(self):
status = "已借出" if self._is_borrowed else "可借阅"
return f"《{self.title}》- {self.author} [{status}]"
class Library:
"""图书馆管理类"""
def __init__(self, name):
self.name = name
self.books = []
def add_book(self, book):
self.books.append(book)
print(f"添加图书: {book.title}")
def remove_book(self, isbn):
for book in self.books:
if book.isbn == isbn:
self.books.remove(book)
print(f"删除图书: {book.title}")
return
print("未找到该图书")
def search(self, keyword):
results = [b for b in self.books if keyword in b.title or keyword in b.author]
return results
def list_books(self):
if not self.books:
print("图书馆暂无图书")
return
for book in self.books:
print(f" {book}")
# 使用
library = Library("中央图书馆")
# 添加图书
library.add_book(Book("Python编程", "张三", "978-1"))
library.add_book(Book("数据结构", "李四", "978-2"))
library.add_book(Book("算法导论", "王五", "978-3"))
print(f"\n📚 {library.name} 所有图书:")
library.list_books()
# 借书
print("\n借书操作:")
library.books[0].borrow()
# 搜索
print("\n搜索 'Python':")
for book in library.search("Python"):
print(f" {book}")
十、总结
| 概念 | 语法 | 说明 |
|---|---|---|
| 类定义 | class 类名: |
首字母大写的驼峰命名 |
| 构造方法 | def __init__(self, ...): |
创建对象时自动调用 |
| 实例方法 | def method(self): |
第一个参数必须是 self |
| 类方法 | @classmethod def method(cls): |
第一个参数是 cls,通过类调用 |
| 静态方法 | @staticmethod def method(): |
不需要 self 或 cls |
| 属性 | self.attr = value |
每个对象独立的属性 |
| 私有属性 | self.__attr = value |
名称改写,外部不易访问 |
| 属性控制 | @property |
控制属性的读写行为 |
| 字符串 | __str__, __repr__ |
自定义对象的字符串表示 |
十一、练习题
练习 1:银行账户类
创建一个 BankAccount 类,支持存款、取款、转账,余额不能为负。
练习 2:向量类
创建 Vector 类,支持向量加法、减法、点积运算,并且能计算向量长度。
练习 3:温度类
创建 Temperature 类,使用 @property 实现摄氏度、华氏度、开尔文之间的自动转换。
参考答案
练习 2 参考答案
python
import math
class Vector:
def __init__(self, *components):
self.components = components
def __add__(self, other):
return Vector(*(a + b for a, b in zip(self.components, other.components)))
def __sub__(self, other):
return Vector(*(a - b for a, b in zip(self.components, other.components)))
def dot(self, other):
return sum(a * b for a, b in zip(self.components, other.components))
def magnitude(self):
return math.sqrt(sum(c ** 2 for c in self.components))
def __str__(self):
return f"Vector{self.components}"
v1 = Vector(1, 2, 3)
v2 = Vector(4, 5, 6)
print(v1 + v2) # Vector(5, 7, 9)
print(v1.dot(v2)) # 32
print(v1.magnitude()) # 3.741...
🎉 恭喜你完成了第27天的学习!面向对象是 Python 编程的核心范式。
📌 下一天预告:第28天 ------ Python面向对象之继承与多继承