【python零基础教程第9讲】继承、多态、魔法函数

【python零基础教程第9讲】继承、多态、魔法函数
Python面向对象编程深度解析继承、多态、魔法函数与高级实践一、继承与多态1.1 单继承子类复用父类代码继承是面向对象编程的核心机制之一允许子类复用父类的属性和方法同时可以扩展或修改已有功能。单继承是最简单的继承形式一个子类只继承一个父类。classContact:all_contacts[]def__init__(self,name,email):self.namename self.emailemail Contact.all_contacts.append(self)classSupplier(Contact):deforder(self,order):print(f向{self.name}下单{order})# 使用sSupplier(张三,zhangsanexample.com)s.order(100件商品)# 输出向 张三 下单100件商品print(s.name)# 输出张三在这个例子中Supplier类继承了Contact类的__init__方法和all_contacts属性并添加了order方法。1.2super()调用父类构造/方法当子类需要扩展父类的初始化逻辑时可以使用super()调用父类的__init__方法避免重复代码并确保父类初始化正确执行。classFriend(Contact):def__init__(self,name,email,phone):super().__init__(name,email)# 调用父类构造self.phone***********Friend(李四,lisiexample.com,***********00)print(f.name,f.phone)# 输出李四 13800138000super()不仅用于构造函数也可以用于普通方法。它按照方法解析顺序MRO调用下一个类的方法在多重继承中尤为重要。1.3 方法重写子类可以重新定义父类的方法实现自己的行为。通过super()可以在重写的方法中调用父类的版本实现扩展而非完全覆盖。classAnimal:defeat(self):print(Animal can eat)classCat(Animal):defeat(self):super().eat()# 调用父类方法print(Cat can eat chicken)catCat()cat.eat()# 输出# Animal can eat# Cat can eat chicken1.4 多态实现多态是指不同类的对象对同一消息做出不同响应的能力。Python 是动态类型语言多态天然支持——只要对象有相应的方法就可以调用。classDog:defspeak(self):return汪汪classCat:defspeak(self):return喵喵defanimal_sound(animal):print(animal.speak())animal_sound(Dog())# 输出汪汪animal_sound(Cat())# 输出喵喵多态让代码更加灵活无需关心对象的具体类型只需保证对象实现了所需的方法。1.5 多继承与MRO方法解析顺序Python 支持多继承一个子类可以同时继承多个父类。这带来了强大的代码复用能力但也引入了方法冲突的问题。classFather:defskills(self):print(园艺、编程)classMother:defskills(self):print(烹饪、音乐)classChild(Father,Mother):defown_skill(self):print(体育)cChild()c.skills()# 输出园艺、编程根据MROFather优先MROMethod Resolution Order是 Python 确定方法调用顺序的机制基于 C3 线性化算法。其核心规则包括子类优先于父类父类声明顺序保留单调性约束可以通过__mro__属性或mro()方法查看print(Child.__mro__)# 输出(class __main__.Child, class __main__.Father, class __main__.Mother, class object)菱形继承问题当多个父类继承自同一个基类时MRO 确保每个类的方法只被调用一次。classA:defmethod(self):print(A)classB(A):defmethod(self):print(B)super().method()classC(A):defmethod(self):print(C)super().method()classD(B,C):defmethod(self):print(D)super().method()dD()d.method()# 输出# D# B# C# Aprint(D.__mro__)# (D, B, C, A, object)协作式继承为了确保所有父类方法都被调用父类方法中应使用super()形成调用链。如果无法修改父类代码可以通过遍历__bases__或__mro__显式调用每个父类的方法。classChild(Parent1,Parent2):defonstart(self):forclsinself.__class__.__mro__:ifonstartincls.__dict__:cls.onstart(self)二、全套魔法函数双下方法__xx__魔法函数是 Python 中名称以双下划线开头和结尾的特殊方法用于实现对象的内置行为。掌握它们可以写出更 Pythonic 的代码。2.1 字符串展示__str__与__repr____str__被str()和print()调用返回用户友好的字符串。__repr__被repr()调用返回开发者友好的字符串通常用于调试应能通过eval()重建对象。classPerson:def__init__(self,name,age):self.namename self.ageagedef__str__(self):returnfPerson:{self.name},{self.age}岁def__repr__(self):returnfPerson({self.name},{self.age})pPerson(小明,25)print(p)# 输出Person: 小明, 25岁print(repr(p))# 输出Person(小明, 25)2.2 长度与索引__len__、__getitem__、__setitem__、__delitem__这些方法让自定义对象支持类似列表或字典的索引操作。classMyList:def__init__(self,items):self.itemslist(items)def__len__(self):returnlen(self.items)def__getitem__(self,index):returnself.items[index]def__setitem__(self,index,value):self.items[index]valuedef__delitem__(self,index):delself.items[index]mlMyList([1,2,3,4])print(len(ml))# 输出4print(ml)# 输出2ml99print(ml)# 输出99delmlprint(ml)# 输出99原索引1变为02.3 运算符重载__add__、__sub__、__mul__通过定义这些方法可以让自定义对象支持、-、*等运算符。classVector:def__init__(self,x,y):self.xx self.yydef__add__(self,other):returnVector(self.xother.x,self.yother.y)def__sub__(self,other):returnVector(self.x-other.x,self.y-other.y)def__mul__(self,scalar):returnVector(self.x*scalar,self.y*scalar)def__repr__(self):returnfVector({self.x},{self.y})v1Vector(1,2)v2Vector(3,4)print(v1v2)# 输出Vector(4, 6)print(v2-v1)# 输出Vector(2, 2)print(v1*3)# 输出Vector(3, 6)2.4 布尔判断__bool__定义__bool__方法可以控制对象在布尔上下文如if语句中的行为。如果未定义Python 会调用__len__长度为0则返回False。classAccount:def__init__(self,balance):self.balancebalancedef__bool__(self):returnself.balance0acc1Account(100)acc2Account(0)print(bool(acc1))# 输出Trueprint(bool(acc2))# 输出False2.5 迭代协议__iter__与__next__实现这两个方法可以让自定义对象支持for循环迭代。classCountDown:def__init__(self,start):self.currentstartdef__iter__(self):returnselfdef__next__(self):ifself.current0:raiseStopIteration valueself.current self.current-1returnvaluefornuminCountDown(5):print(num,end )# 输出5 4 3 2 12.6 上下文魔法__enter__与__exit__实现这两个方法可以让对象支持with语句自动管理资源如文件、锁。classManagedFile:def__init__(self,filename,mode):self.filenamefilename self.modemodedef__enter__(self):self.fileopen(self.filename,self.mode)returnself.filedef__exit__(self,exc_type,exc_val,exc_tb):ifself.file:self.file.close()# 返回 False 表示不抑制异常True 表示抑制returnFalsewithManagedFile(test.txt,w)asf:f.write(Hello, World!)# 文件自动关闭2.7 哈希与判等__eq__与__hash____eq__定义对象相等比较逻辑。__hash__定义对象的哈希值用于字典键和集合成员。如果定义了__eq__通常也需要定义__hash__且相等的对象哈希值应相同。classPoint:def__init__(self,x,y):self.xx self.yydef__eq__(self,other):ifnotisinstance(other,Point):returnNotImplementedreturnself.xother.xandself.yother.ydef__hash__(self):returnhash((self.x,self.y))def__repr__(self):returnfPoint({self.x},{self.y})p1Point(1,2)p2Point(1,2)p3Point(3,4)print(p1p2)# 输出Trueprint(p1p3)# 输出Falseprint(hash(p1)hash(p2))# 输出True# 可以用作字典键d{p1:origin}print(d[p2])# 输出origin2.8 对象生命周期__new__与__del____new__在__init__之前调用用于创建实例控制实例创建过程常用于单例模式。__del__对象被销毁时调用析构函数用于清理资源。classSingleton:_instanceNonedef__new__(cls,*args,**kwargs):ifcls._instanceisNone:cls._instancesuper().__new__(cls)returncls._instancedef__init__(self,value):self.valuevaluedef__del__(self):print(fSingleton with value{self.value}is being destroyed)s1Singleton(10)s2Singleton(20)print(s1iss2)# 输出True单例print(s1.value)# 输出20因为s2覆盖了s1三、OOP综合拓展3.1 抽象基类ABC强制子类实现方法抽象基类Abstract Base Class用于定义接口强制子类必须实现某些方法。Python 通过abc模块实现。fromabcimportABC,abstractmethodclassShape(ABC):abstractmethoddefarea(self):passabstractmethoddefperimeter(self):passclassCircle(Shape):def__init__(self,radius):self.radiusradiusdefarea(self):return3.14*self.radius**2defperimeter(self):return2*3.14*self.radius# 尝试实例化抽象类会报错# s Shape() # TypeError: Cant instantiate abstract class ShapecCircle(5)print(c.area())# 输出78.5print(c.perimeter())# 输出31.400000000000002抽象基类在大型项目中非常有用可以确保所有子类遵循统一的接口规范。3.2 类装饰器简易用法类装饰器是一种修改类行为的函数接收类作为参数并返回修改后的类或新类。常用于添加属性、方法或修改元数据。defadd_repr(cls):为类自动添加 __repr__ 方法def__repr__(self):attrs, .join(f{k}{v}fork,vinself.__dict__.items())returnf{cls.__name__}({attrs})cls.__repr____repr__returnclsadd_reprclassBook:def__init__(self,title,author):self.titletitle self.authorauthor bBook(Python编程,张三)print(b)# 输出Book(titlePython编程, author张三)类装饰器也可以用于注册类、添加缓存、实现单例等高级功能。3.3 三大特性总结封装、继承、多态实战面向对象编程的三大特性——封装、继承、多态——在实际开发中相辅相成。下面通过一个综合示例展示它们的应用fromabcimportABC,abstractmethod# 1. 封装将数据和操作封装在类中classBankAccount(ABC):def__init__(self,owner,balance0):self._ownerowner# 受保护属性self.__balancebalance# 私有属性名称修饰defdeposit(self,amount):ifamount0:self.__balanceamountprint(f存款{amount}余额{self.__balance})defwithdraw(self,amount):if0amountself.__balance:self.__balance-amountprint(f取款{amount}余额{self.__balance})else:print(余额不足)defget_balance(self):returnself.__balanceabstractmethoddefdescribe(self):pass# 2. 继承子类复用父类代码并扩展classSavingsAccount(BankAccount):def__init__(self,owner,balance0,interest_rate0.02):super().__init__(owner,balance)self.interest_rateinterest_ratedefapply_interest(self):interestself.get_balance()*self.interest_rate self.deposit(interest)print(f利息{interest:.2f}已添加)defdescribe(self):returnf储蓄账户 - 户主{self._owner}利率{self.interest_rate*100}%classCheckingAccount(BankAccount):def__init__(self,owner,balance0,overdraft_limit1000):super().__init__(owner,balance)self.overdraft_limitoverdraft_limitdefwithdraw(self,amount):ifamountself.get_balance()self.overdraft_limit:# 重写取款方法允许透支ifamountself.get_balance():print(使用透支额度)super().withdraw(amount)else:print(超过透支限额)defdescribe(self):returnf支票账户 - 户主{self._owner}透支限额{self.overdraft_limit}# 3. 多态不同对象对同一消息做出不同响应defshow_account_info(account):print(account.describe())print(f当前余额{account.get_balance()})# 使用savingsSavingsAccount(Alice,1000,0.03)checkingCheckingAccount(Bob,500,2000)savings.deposit(500)savings.apply_interest()show_account_info(savings)# 输出# 存款 500余额1500# 利息 45.00 已添加# 存款 45余额1545# 储蓄账户 - 户主Alice利率3.0%# 当前余额1545checking.withdraw(2000)# 使用透支额度show_account_info(checking)# 输出# 使用透支额度# 取款 2000余额-1500# 支票账户 - 户主Bob透支限额2000# 当前余额-1500总结Python 的面向对象编程提供了丰富的机制来构建可维护、可扩展的代码继承通过单继承和多继承实现代码复用super()和 MRO 确保方法调用的正确性。多态让代码更加灵活无需关心对象的具体类型。魔法函数赋予自定义对象与内置类型一致的行为从字符串展示到运算符重载从迭代到上下文管理。抽象基类强制子类实现接口保证代码的规范性。类装饰器提供了一种优雅的方式修改类行为。在实际开发中应遵循“组合优于继承”的原则谨慎使用多继承优先使用混入Mixin模式。理解这些核心概念将帮助你写出更 Pythonic、更健壮的代码。

最新新闻

日新闻

周新闻

月新闻