Python面向对象编程(OOP)高级详解

张开发
2026/4/6 17:34:29 15 分钟阅读

分享文章

Python面向对象编程(OOP)高级详解
目录一、Python中的继承1. 什么是继承2. 继承的基本语法3. 与继承相关的几个概念4. 单继承5. 单继承(多层继承)6. 编写面向对象代码中的常见问题6.1 类名问题6.2 继承问题6.3 书写问题7. 多继承8. 子类重写父类属性和方法9. super()调用父类属性和方法10. MRO方法解析顺序二、Python中的多态1. 什么是多态多态原理图2. 多态示例扩展在Python中还有哪些多态的案例呢三、面向对象其他特性1. 类属性2. 类方法3. 静态方法4. 综合案例前言在掌握了面向对象的基础知识类、对象、封装后我们接下来去学习Python中的继承、多态以及类属性、类方法和静态方法。一、Python中的继承1. 什么是继承类是用来描述现实世界中同一组事物的共有特性的抽象模型但是类也有上下级和范围之分比如生物 - 动物 - 哺乳动物 - 灵长型动物 - 人类 - 黄种人从哲学上说就是共性与个性之间的关系比如白马和马所以我们在OOP代码中也一样要体现出类与类之间的共性与个性关系这里就需要通过类的继承来体现。简单来说如果一个类A使用了另一个类B的成员属性和方法我们就可以说A类继承了B类同时这也体现了OOP中代码重用的特性2. 继承的基本语法假设A类要继承B类中的所有属性和方法私有属性和私有方法除外class B(object): pass class A(B): pass a A() a.B中的所有公共属性 a.B中的所有公共方法示例Person类与Teacher、Student类之间的继承关系python class Person: def eat(self): print(i can eat food!) def speak(self): print(i can speak!) class Teacher(Person): pass class Student(Person): pass teacher Teacher() teacher.eat() # 继承自Person teacher.speak() student Student() student.eat() # 继承自Person student.speak() # 运行结果 i can eat food! i can speak! i can eat food! i can speak!3. 与继承相关的几个概念继承一个类从另一个已有的类获得其成员的特性。派生从一个已有的类产生一个新的类称为派生。与继承是同一过程的两个方向。父类基类被继承的类。子类派生类继承自父类的类。扩展在子类中增加一些自己特有的特性就叫作扩展没有扩展继承也就没有意义了单继承一个类只能继承自一个父类。多继承一个类可以同时继承多个父类Python支持但是java不支持。4. 单继承单继承是最常见的继承形式一个子类只继承一个父类,不能同时继承多个类。这个类会有具有父类的属性和方法。基本语法# 1、定义一个共性类父类 class Person(object): pass # 2、定义一个个性类子类 class Student(Person): pass示例汽车类 Car汽油车 GasolineCar 和电动车 ElectricCar 分别继承它。python # 1、定义一个共性类车类 class Car: def run(self): print(I can run) # 2、定义汽油车 class GasolineCar(Car): pass # 3、定义电动车 class ElectricCar(Car): pass bwm GasolineCar() bwm.run() # 输出I can run5. 单继承(多层继承)Python支持多层继承即子类可以再被继承形成继承链,所有上层的公共方法都会被传递下来。如A类继承了B类B类又继承了C类。则根据继承的传递性则A类也会自动继承C类中所有属性和方法公共。python class C: def func(self): print(我是C类中的方法func) class B(C): pass class A(B): pass a A() a.func() # 输出我是C类中的方法func6. 编写面向对象代码中的常见问题6.1 类名问题在定义类时其没有遵循类的命名规则在Python中类理论上是区分大小写的在Python中类可以全部大写也可以全部小写。但是要遵循一定的命名规范首字母必须是字母或下划线其中可以包含字母、数字和下划线而且要求其命名方式采用大驼峰。例如电动汽车EletricCar父类Father子类Son6.2 继承问题问父类一定要继承object么Car(object)答在Python面向对象代码中建议在编写父类时让其自动继承object类。但是其实不写也可以因为默认情况下Python中的所有类都继承自object。6.3 书写问题初始化对象属性的魔法方法很容易写错在定义魔术方法__init__名字经常会错误的写为__int__。7. 多继承Python支持多继承一个子类可以同时继承多个父类。基本语法class B(object): pass class C(object): pass class A(B, C): pass a A() a.B中的所有属性和方法 a.C中的所有属性和方法案例汽油车、电动车 - 混合动力汽车汽车 电动python class GasolineCar: def run_with_gasoline(self): print(i can run with gasoline) class ElectricCar: def run_with_electric(self): print(i can run with electric) class HybridCar(GasolineCar, ElectricCar): pass tesla HybridCar() tesla.run_with_gasoline() # 输出i can run with gasoline tesla.run_with_electric() # 输出i can run with electric注意虽然多继承允许我们同时继承自多个类但是实际开发中应尽量避免使用多继承因为如果两个类中出现了相同的属性和方法就会产生命名冲突。当多个父类有同名方法时Python会按照方法解析顺序MRO来查找。8. 子类重写父类属性和方法重写也叫作覆盖就是当子类成员与父类成员名字相同的时候从父类继承下来的成员会重新定义此时通过子类实例化出来的对象访问相关成员的时候真正其作用的是子类中定义的成员注意: 如果子类中的属性和方法与父类中的属性或方法同名则子类中的属性或方法会对父类中同名的属性或方法进行覆盖重写class Father(object): # 属性 # 方法 class Son(Father): # 默认继承父类属性和方法 # 自己的属性和方法重写的意义?继承让子类继承父类的所有公共属性和方法但是如果仅仅是为了继承公共属性和方法继承就没有实际的意义了应该是在继承以后子类应该有一些自己的属性和方法。Animal 的子类 Cat和Dog 继承了父类的属性和方法但是我们狗类Dog 有自己的叫声汪汪叫猫类 Cat 有自己的叫声 喵喵叫 这时我们需要对父类的 call() 方法进行重构。如下class Animal(object): def eat(self): print(i can eat) def call(self): print(i can call) class Dog(Animal): pass class Cat(Animal): pass wangcai Dog() wangcai.eat() wangcai.call() miaomiao Cat() miaomiao.eat() miaomiao.call() # 运行结果 i can eat i can call i can eat i can callDog 和 Cat 重写 Animal 的 call 方法python class Animal: def eat(self): print(吃) def call(self): print(叫) class Dog(Animal): def call(self): print(汪汪叫) class Cat(Animal): def call(self): print(喵喵叫) wangcai Dog() wangcai.eat() # 继承自Animal wangcai.call() # 输出汪汪叫 miaomiao Cat() miaomiao.eat() miaomiao.call() # 输出喵喵叫思考重写父类中的call方法以后此时父类中的call方法还在不在答还在只不过是在其子类中找不到了。类方法的调用顺序当我们在子类中重构父类的方法后Cat子类的实例先会在自己的类 Cat 中查找该方法当找不到该方法时才会去父类 Animal 中查找对应的方法。9. super()调用父类属性和方法super()作用调用父类属性或方法super()完整写法super(当前类名, self).属性或方法()在Python3以后版本中调用父类的属性和方法我们只需要使用super().属性或super().方法名()就可以完成调用了。示例电动车 ElectricCar 继承 Car在 __init__ 和 run 方法中调用父类。python class Car: def __init__(self, brand, model, color): self.brand brand self.model model self.color color def run(self): print(i can run) class ElectricCar(Car): def __init__(self, brand, model, color, battery): super().__init__(brand, model, color) self.battery battery def run(self): super().run() print(fi can run with electric, battery: {self.battery} kWh) tesla ElectricCar(特斯拉, Model S, 红色, 70) tesla.run() 运行结果 i can run i can run with electric, battery: 70 kWh10. MRO方法解析顺序MRO决定了在继承链中方法的查找顺序。可以通过 类名.__mro__ 或 类名.mro() 查看。python class Car: pass class GasolineCar(Car): pass class ElectricCar(Car): pass class HybridCar(GasolineCar, ElectricCar): pass print(HybridCar.__mro__) 运行结果示例 (class __main__.HybridCar, class __main__.GasolineCar, class __main__.ElectricCar, class __main__.Car, class object)MRO查找规则从当前类开始依次向上查找直到找到对应方法或到达 object。二、Python中的多态1. 什么是多态多态指的是一类事物有多种形态。定义多态是一种使用对象的方式子类重写父类方法调用不同子类对象的相同父类方法可以产生不同的执行结果。不同对象 - 使用相同方法 - 产生不同的执行结果。多态的三要素存在继承关系不是必须但常见子类重写父类方法使用父类类型的变量指向子类对象调用同一方法多态好处调用灵活有了多态更容易编写出通用的代码做出通用的编程以适应需求的不断变化。多态原理图公共接口service就是多态的体现随着传入水果对象的不同能返回不同的结果。2. 多态示例多态可以基于继承也可以不基于继承python 首先定义一个父类其可能拥有多个子类对象。 当我们调用一个公共方法接口时传递的对象不同则返回的结果不同。 class Fruit: def makejuice(self): print(i can make juice) class Apple(Fruit): # 重写父类方法 def makejuice(self): print(i can make apple juice) class Banana(Fruit): # 重写父类方法 def makejuice(self): print(i can make banana juice) class Orange(Fruit): # 重写父类方法 def makejuice(self): print(i can make orange juice) # 定义一个公共接口专门用于实现榨汁操作 def service(obj): # obj要求是一个实例化对象可以传入苹果对象/香蕉对象 obj.makejuice() # 调用公共方法 service(Apple()) # 输出i can make apple juice service(Banana()) # 输出i can make banana juice service(Orange()) # 输出i can make orange juice扩展在Python中还有哪些多态的案例呢 多态体现加号只有一个但是不同的对象调用方法其返回结果不同。如果加号的两边都是数值类型的数据则加号代表运算符。如果加号的两边传入的是字符串类型的数据则加号代表合并操作返回合并后的字符串a b ab。如果加号的两边出入序列类型的数据则加号代表合并操作返回合并后的序列[1, 2, 3] [4, 5, 6] [1, 2, 3, 4, 5, 6]。三、面向对象其他特性1. 类属性类属性是定义在类中、属于类本身的属性被该类的所有实例共享。通常用于记录与类相关的特征如计数、配置等不会用于记录具体对象的特征。在Python中一切皆对象。类也是一个特殊的对象我们可以单独为类定义属性python class Person: count 0 # 类属性用于记录实例个数 def __init__(self, name): self.name name Person.count 1 p1 Person(Tom) p2 Person(Jerry) print(f我们共创建了 {Person.count} 个Person对象) # 输出22. 类方法为什么需要类方法在面向对象中特别强调数据封装性。所以不建议直接在类的外部对类属性进行直接获取。所以我们如果想操作类属性建议使用类方法。类方法用于操作类属性或执行与类相关的操作使用 classmethod 装饰器定义第一个参数是 cls类本身。python class Tool: count 0 def __init__(self, name): self.name name Tool.count 1 classmethod def get_count(cls): print(f共创建了 {cls.count} 个工具) t1 Tool(斧头) t2 Tool(榔头) t3 Tool(铁锹) Tool.get_count() # 输出共创建了 3 个工具3. 静态方法在开发时如果需要在类中封装一个方法这个方法① 既不需要访问实例属性或者调用实例方法② 也不需要访问类属性或者调用类方法这个时候可以把这个方法封装成一个静态方法静态方法与类或实例没有直接关联只是逻辑上属于类使用 staticmethod 装饰器定义。不需要 self 或 cls 参数。python class Game: staticmethod def show_help(): print(1. 开始游戏) print(2. 暂停游戏) print(3. 退出游戏) Game.show_help() # 运行结果 1. 开始游戏 2. 暂停游戏 3. 退出游戏4. 综合案例设计一个 Game 类包含类属性历史最高分、实例属性玩家姓名、静态方法显示帮助、类方法显示历史最高分、实例方法开始游戏。python class Game: top_score 0 # 类属性历史最高分 def __init__(self, player_name): self.player_name player_name staticmethod def show_help(): print(【Start】开始游戏) print(【Stop】结束游戏) print(【Help】查看帮助) classmethod def show_top_score(cls): print(f本游戏历史最高分{cls.top_score}) def start_game(self): print(f{self.player_name} 开始游戏) # 调用静态方法 Game.show_help() # 调用类方法 Game.show_top_score() # 创建实例调用实例方法 player Game(张三) player.start_game() # 运行结果 【Start】开始游戏 【Stop】结束游戏 【Help】查看帮助 本游戏历史最高分0 张三 开始游戏如果觉得本文对你有帮助欢迎点赞、收藏、转发有任何问题欢迎在评论区留言交流。

更多文章