Day 25:面向对象(上)------类与对象
函数是"把代码打包",面向对象是"把数据和操作数据的函数打包在一起"。今天学面向对象编程(OOP)的核心概念:类(class)和对象(object)。
一、为什么要面向对象?
假设你要管理很多学生的信息:
python
# 面向过程的写法:数据和操作分离
student1_name = "小明"
student1_score = 85
student2_name = "小红"
student2_score = 92
def print_student(name, score):
print(f"{name}: {score}分")
print_student(student1_name, student1_score)
如果还要加年龄、城市、课程列表......变量越来越多,很容易搞混。
面向对象把数据和行为绑定在一起:
python
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def print_info(self):
print(f"{self.name}: {self.score}分")
# 创建对象(实例化)
s1 = Student("小明", 85)
s2 = Student("小红", 92)
s1.print_info() # 小明: 85分
s2.print_info() # 小红: 92分
二、类 = 蓝图,对象 = 实物
- 类(class):一张设计蓝图,定义了"学生应该有什么属性和方法"
- 对象(object):根据蓝图造出来的具体实例
python
class Dog:
"""狗类"""
# 类属性(所有实例共享)
species = "Canis familiaris"
# __init__ 是构造方法,创建对象时自动调用
def __init__(self, name, age):
# 实例属性(每个实例自己的数据)
self.name = name
self.age = age
# 实例方法(第一个参数必须是 self)
def bark(self):
print(f"{self.name}:汪汪!")
def info(self):
return f"{self.name},{self.age}岁,{self.species}"
# 创建实例
dog1 = Dog("旺财", 3)
dog2 = Dog("大黄", 5)
dog1.bark() # 旺财:汪汪!
print(dog1.info()) # 旺财,3岁,Canis familiaris
print(dog2.info()) # 大黄,5岁,Canis familiaris
三、class 的核心三要素
1. __init__ ------ 构造函数
python
class Book:
def __init__(self, title, author, pages=0):
self.title = title
self.author = author
self.pages = pages
print(f"创建了《{title}》")
# 创建对象时传入参数,__init__ 自动执行
b = Book("三体", "刘慈欣", 300)
# 输出:创建了《三体》
2. self ------ 指代"自己"
python
class Counter:
def __init__(self):
self.count = 0 # self.count 是"这个实例的 count"
def increment(self):
self.count += 1 # 修改"自己"的 count
print(f"当前计数:{self.count}")
c1 = Counter()
c2 = Counter()
c1.increment() # 1
c1.increment() # 2
c2.increment() # 1 (c2 是另一个实例,count 独立)
self 不是关键字,写成 this 也可以(但不建议,社区规定用 self)。调用时不需要传 self,Python 会自动传。
3. 实例属性 vs 类属性
python
class Student:
school = "海淀小学" # 类属性(所有实例共享)
def __init__(self, name):
self.name = name # 实例属性(每个实例独立)
s1 = Student("小明")
s2 = Student("小红")
print(s1.school) # 海淀小学
print(s2.school) # 海淀小学
# 修改类属性 → 所有人都变了
Student.school = "朝阳小学"
print(s1.school) # 朝阳小学
# 但如果通过实例赋值 → 只给这个实例创建了同名的实例属性
s1.school = "自定义学校"
print(s1.school) # 自定义学校(实例属性覆盖了类属性)
print(s2.school) # 朝阳小学(还是类属性)
四、实战:银行账户类
python
class BankAccount:
"""银行账户"""
# 类属性
bank_name = "中国银行"
total_accounts = 0
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
self.transactions = [] # 交易记录
BankAccount.total_accounts += 1
def deposit(self, amount):
"""存款"""
if amount <= 0:
print("存款金额必须大于0")
return False
self.balance += amount
self.transactions.append(f"存入 +{amount}")
print(f"存款成功!余额:{self.balance}")
return True
def withdraw(self, amount):
"""取款"""
if amount <= 0:
print("取款金额必须大于0")
return False
if amount > self.balance:
print(f"余额不足!当前余额:{self.balance}")
return False
self.balance -= amount
self.transactions.append(f"取出 -{amount}")
print(f"取款成功!余额:{self.balance}")
return True
def show_info(self):
print(f"\n户主:{self.owner}")
print(f"银行:{self.bank_name}")
print(f"余额:{self.balance}元")
print(f"交易记录:")
for t in self.transactions:
print(f" {t}")
# 使用
acc1 = BankAccount("小明", 1000)
acc1.deposit(500)
acc1.withdraw(200)
acc1.show_info()
acc2 = BankAccount("小红", 2000)
print(f"\n总开户数:{BankAccount.total_accounts}") # 2
五、__str__ 和 __repr__------让打印更友好
python
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __str__(self):
"""print() 时调用,给用户看的"""
return f"学生 {self.name},成绩 {self.score} 分"
def __repr__(self):
"""调试时调用,给开发者看的"""
return f"Student(name='{self.name}', score={self.score})"
s = Student("小明", 85)
print(s) # 学生 小明,成绩 85 分
print(repr(s)) # Student(name='小明', score=85)
六、今日学习总结
| 学习内容 | 掌握情况 | 一句话要点 |
|---|---|---|
| 类 vs 对象 | ✅ 理解 | 类是蓝图,对象是实物 |
__init__ 构造方法 |
✅ 重点 | 创建对象时自动调用,初始化属性 |
self 参数 |
✅ 重点 | 指代当前实例,调用时不用传 |
| 实例属性 vs 类属性 | ✅ 理解 | 实例属性 self.x,类属性直接写在类里 |
__str__ / __repr__ |
✅ 了解 | 控制打印输出 |
今日踩坑记录
- 忘记写 self :
def deposit(amount):会报错 "takes 1 argument but 2 were given"。第一个参数必须是 self。 - 把所有属性都写成类属性 :
class Student: name = ""这种写法所有实例共享 name,改一个全都改。实例属性必须写在__init__里用self.xxx。 print(对象)显示<__main__.Student at 0x...>:因为没有定义__str__方法,Python 只能用默认的表示。加上__str__就好了。
七、明天学什么?
今天学会了创建简单的类和对象。明天继续 OOP 进阶------继承、多态、封装,这是面向对象的三大支柱。
面向对象是一种思维方式:先想"有什么东西"(对象),再想"它们能做什么"(方法)。用现实世界的方式理解代码。
第25天,打卡完成。明天见!
本系列是个人学习笔记,如有错误欢迎在评论区指正交流。