day-026-面向对象-中
Day 26面向对象中——继承、多态与封装昨天学了类和对象的基本写法。今天搞定面向对象的三大特性——封装藏起来、继承复用别人、多态灵活替换。一、封装——把数据保护起来封装就是控制外部对内部数据的访问权限避免外部代码直接乱改。classBankAccount:def__init__(self,owner,balance0):self.ownerowner self._balancebalance# 单下划线约定私有别碰self.__pin1234# 双下划线名称改写更难访问propertydefbalance(self):用 property 把方法伪装成属性returnself._balancebalance.setterdefbalance(self,value):设置余额时加校验ifvalue0:raiseValueError(余额不能为负)self._balancevaluedefdeposit(self,amount):ifamount0:raiseValueError(存款金额必须大于0)self._balanceamountdefwithdraw(self,amount):ifamountself._balance:raiseValueError(余额不足)self._balance-amount# 使用 propertyaccBankAccount(小明,1000)print(acc.balance)# 1000 像属性一样访问实际调用了方法acc.balance2000# 会触发 balance.setter 的校验print(acc.balance)# 2000# acc.__pin # AttributeError双下划线被改写了# acc._BankAccount__pin # 可以强行访问但说明你不应该碰Python 的哲学我们都是成年人Python 的封装哲学_name单下划线约定私有大家遵守但不强制__name双下划线名称改写name mangling防意外覆盖用property装饰器实现受控的属性访问property 实战classStudent:def__init__(self,name,score):self.namename self._scorescorepropertydefscore(self):returnself._scorescore.setterdefscore(self,value):ifnot0value100:raiseValueError(成绩必须在 0-100 之间)self._scorevaluepropertydefgrade(self):年级是计算得出的不是存储的ifself._score90:returnAelifself._score80:returnBelifself._score60:returnCelse:returnDsStudent(小明,85)print(s.grade)# B 只读属性没有 setters.score92# OKprint(s.grade)# A# s.score -5 # ValueError!二、继承——复用父类的代码继承让你创建新类时复用已有类的属性和方法# 父类基类classAnimal:def__init__(self,name):self.namenamedefspeak(self):pass# 子类自己实现definfo(self):returnf我是{self.name}# 子类继承父类classDog(Animal):defspeak(self):returnf{self.name}汪汪deffetch(self):returnf{self.name}去捡球了classCat(Animal):defspeak(self):returnf{self.name}喵喵# 使用dogDog(旺财)catCat(咪咪)print(dog.info())# 我是 旺财 继承了父类的 info 方法print(dog.speak())# 旺财汪汪 覆盖了父类的方法print(dog.fetch())# 旺财 去捡球了 自己的新方法print(cat.speak())# 咪咪喵喵super()——调用父类方法classAnimal:def__init__(self,name,age):self.namename self.ageageclassDog(Animal):def__init__(self,name,age,breed):super().__init__(name,age)# 先调用父类的 __init__self.breedbreed# 再初始化自己的属性definfo(self):returnf{self.name}{self.age}岁{self.breed}犬dogDog(旺财,3,金毛)print(dog.info())# 旺财3岁金毛犬多重继承classFlyable:deffly(self):return飞起来了classSwimmable:defswim(self):return游起来了classDuck(Animal,Flyable,Swimmable):defspeak(self):return嘎嘎duckDuck(唐老鸭,2)print(duck.fly())# 飞起来了 (Flyable)print(duck.swim())# 游起来了 (Swimmable)print(duck.speak())# 嘎嘎 (Duck)多重继承很强大但也容易混乱。大多数情况用单继承就够了。三、多态——同一个接口不同行为多态的意思是同一个方法名不同的类有不同的实现调用方不需要知道具体是哪个类classCircle:def__init__(self,radius):self.radiusradiusdefarea(self):return3.14159*self.radius**2classRectangle:def__init__(self,width,height):self.widthwidth self.heightheightdefarea(self):returnself.width*self.heightclassTriangle:def__init__(self,base,height):self.basebase self.heightheightdefarea(self):return0.5*self.base*self.height# 多态体现不管什么形状都调用 area()各自按自己的方式计算defprint_area(shape):这个函数不关心 shape 是什么类只要有 area() 方法就行print(f面积{shape.area()})shapes[Circle(5),Rectangle(4,6),Triangle(3,8)]forshapeinshapes:print_area(shape)# 面积78.53975# 面积24# 面积12.0这就是“鸭子类型”如果它走路像鸭子叫起来像鸭子那它就是鸭子。Python 不关心对象的类型只关心它有没有需要的方法。四、实战——用户系统classUser:用户基类def__init__(self,username,email):self.usernameusername self.emailemail self._is_activeTruedeflogin(self):returnf{self.username}登录成功defget_permissions(self):return[read]# 所有人都有读权限def__str__(self):returnfUser({self.username})classAdmin(User):管理员——拥有全部权限defget_permissions(self):permssuper().get_permissions()returnperms[write,delete,manage_users]defdelete_user(self,user):ifnotisinstance(user,User):raiseTypeError(只能删除 User 实例)returnf管理员{self.username}删除了{user.username}classGuest(User):访客——只能读自己的信息def__init__(self,username,email,session_expire):super().__init__(username,email)self.session_expiresession_expiredeflogin(self):returnf访客{self.username}登录有效期至{self.session_expire}defget_permissions(self):return[read_self]# 只能看自己# 使用adminAdmin(admin_zhang,zhangadmin.com)guestGuest(visitor_001,visitortest.com,2026-05-22)print(admin.login())# admin_zhang 登录成功print(admin.get_permissions())# [read, write, delete, manage_users]print(guest.login())# 访客 visitor_001 登录有效期至 2026-05-22print(guest.get_permissions())# [read_self]五、今日学习总结学习内容掌握情况一句话要点封装 property✅ 重点方法假装属性可加校验逻辑单下划线 / 双下划线✅ 理解_x约定私有__x名称改写继承 class Child(Parent)✅ 重点复用父类的代码super()✅ 重点调用父类方法方法重写✅ 理解子类覆盖父类的方法多态 / 鸭子类型✅ 理解不在乎类型只在乎有没有那个方法今日踩坑记录子类__init__没调super().__init__导致父类的初始化代码没执行属性丢失。子类有__init__时第一行通常就是super().__init__()。property和属性同名property的方法名不要和底层存储属性同名通常一个score一个_score否则会无限递归。多重继承的 MRO多重继承时方法查找顺序可能出乎意料。用类名.__mro__查看方法解析顺序。六、明天学什么OOP 最后一篇——特殊方法__len__、__getitem__等、类方法和静态方法然后做一个完整的面向对象小项目。封装保护数据继承减少重复多态让代码灵活。三者合在一起才是面向对象编程的力量。第26天打卡完成。明天见本系列是个人学习笔记如有错误欢迎在评论区指正交流。