面向对象编程
学习目标
- 理解面向对象编程(OOP)的基本思想
- 掌握类和对象的定义与使用
- 理解属性和方法
- 掌握继承、封装的基本用法
- 了解常用的魔术方法
为什么需要面向对象?
假设你在开发一个学生管理系统,需要记录每个学生的信息:
# 用变量和字典的方式
student1_name = "张三"
student1_age = 20
student1_scores = [85, 92, 78]
student2_name = "李四"
student2_age = 21
student2_scores = [90, 88, 95]
# 或者用字典
student1 = {"name": "张三", "age": 20, "scores": [85, 92, 78]}
student2 = {"name": "李四", "age": 21, "scores": [90, 88, 95]}
# 计算平均分的函数
def get_average(student):
return sum(student["scores"]) / len(student["scores"])
这样写有几个问题:
- 数据和操作是分离的(学生数据在字典里,计算函数在外面)
- 没有约束(谁都可以往字典里加奇怪的键,或者删掉必要的键)
- 当学生的属性越来越多时,代码会越来越乱
面向对象编程的思路是:把数据和操作打包在一起,形成一个"对象"。
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)
# 创建学生对象
student1 = Student("张三", 20, [85, 92, 78])
student2 = Student("李四", 21, [90, 88, 95])
# 数据和操作绑在一起,使用起来更自然
print(f"{student1.name} 的平均分: {student1.get_average():.1f}")
print(f"{student2.name} 的平均分: {student2.get_average():.1f}")
类和 对象的基本概念
用一个生活中的类比:
- 类(Class) = 蓝图/模板。比如"手机"是一个概念/类别
- 对象(Object/Instance) = 用蓝图造出来的实体。比如"你手里的那台 iPhone 15"
类:Student(学生的模板)
└── 属性:name, age, scores
└── 方法:get_average(), is_passed()
对象(实例):
└── student1 = Student("张三", 20, [85, 92, 78])
└── student2 = Student("李四", 21, [90, 88, 95])
定义类
最简单的类
class Dog:
"""一只狗"""
def __init__(self, name, breed):
"""初始化方法,创建对象时自动调用"""
self.name = name # 实例属性
self.breed = breed # 实例属性
def bark(self):
"""方法:狗叫"""
print(f"{self.name} 说: 汪汪汪!")
def info(self):
"""方法:显示信息"""
print(f"名字: {self.name}, 品种: {self.breed}")
# 创建对象(实例化)
my_dog = Dog("旺财", "金毛")
your_dog = Dog("小黑", "拉布拉多")
# 访问属性
print(my_dog.name) # 旺财
print(your_dog.breed) # 拉布拉多
# 调用方法
my_dog.bark() # 旺财 说: 汪汪汪!
your_dog.info() # 名字: 小黑, 品种: 拉布拉多
关键点解读
1. __init__ 方法(构造方法)
__init__ 在你创建对象时自动调用,用来初始化对象的属性。
my_dog = Dog("旺财", "金毛")
# Python 自动做了这些事:
# 1. 创建一个新的 Dog 对象
# 2. 调用 __init__(self, "旺财", "金毛")
# 3. self.name = "旺财"
# 4. self.breed = "金毛"
# 5. 返回这个对象给 my_dog
2. self 是什么?
self 代表对象自己。当你调用 my_dog.bark() 时,Python 会自动把 my_dog 作为 self 传给 bark 方法。
my_dog.bark()
# 等价于
Dog.bark(my_dog)
所以 self.name 就是"这个对象的 name"。
self 的命名
self 只是一个惯例(convention),你可以叫它 this 或任何名字,但强烈建议用 self——这是所有 Python 程序员的约定。
属性和方法
实例属性 vs 类属性
class Student:
# 类属性:所有实例共享
school = "Python 大学"
student_count = 0
def __init__(self, name, age):
# 实例属性:每个实例独有
self.name = name
self.age = age
Student.student_count += 1 # 每创建一个学生,计数加 1
s1 = Student("张三", 20)
s2 = Student("李四", 21)
# 类属性通过类名或实例都能访问
print(Student.school) # Python 大学
print(s1.school) # Python 大学
print(Student.student_count) # 2
# 实例属性只属于各自的实例
print(s1.name) # 张三
print(s2.name) # 李四
方法
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
"""计算面积"""
return 3.14159 * self.radius ** 2
def perimeter(self):
"""计算周长"""
return 2 * 3.14159 * self.radius
def scale(self, factor):
"""缩放半径"""
self.radius *= factor # 修改属性
c = Circle(5)
print(f"面积: {c.area():.2f}") # 78.54
print(f"周长: {c.perimeter():.2f}") # 31.42
c.scale(2) # 半径变为 10
print(f"缩放后面积: {c.area():.2f}") # 314.16
魔术方法(双下划线方法)
Python 中以 __ 开头和结尾的方法叫魔术方法(Magic Methods),它们让你的类可以像内置类型一样使用。
__str__:定义 print 的输出
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"Student({self.name}, {self.age}岁)"
s = Student("张三", 20)
print(s) # Student(张三, 20岁)
# 如果没有 __str__,print 会输出 <__main__.Student object at 0x...>
__repr__:定义开发者看到的表示
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"Student('{self.name}', {self.age})"
s = Student("张三", 20)
print(repr(s)) # Student('张三', 20)
# 在交互模式中直接输入 s 也会显示这个
__len__:定义 len() 的行为
class Playlist:
def __init__(self, name, songs):
self.name = name
self.songs = songs
def __len__(self):
return len(self.songs)
my_playlist = Playlist("学习音乐", ["歌曲A", "歌曲B", "歌曲C"])
print(len(my_playlist)) # 3