Python面向对象的三大特性(继承和多态)

本文详细介绍了Python中的面向对象编程特性,包括继承的原理、语法、单继承与多继承的区别,以及多态的概念和实现。通过实例展示了如何利用继承和多态进行代码复用和灵活性提升。

Python面向对象的三大特性(继承和多态)

一、Python中的继承

1、什么是继承

我们接下来来聊聊Python代码中的“继承”:类是用来描述现实世界中同一组事务的共有特性的抽象模型,但是类也有上下级和范围之分,比如:生物 => 动物 => 哺乳动物 => 灵长型动物 => 人类 => 黄种人

简单来说,如果一个类A使用了另一个来


2、继承的基本语法

假设A类要继承B类中的所有属性和方法(私有属性和私有方法除外)

class B(object):
    pass

class A(B):
    pass

a = A()
a.B中的所有公共属性
a.B中的所有公共方法

案例:Person类与Teacher、Student类之间的继承关系

class Person(object):
    def eat(self):
        print('需要吃食物')

    def drink(self):
        print('需要喝水')


class Teacher(Person):
    pass


class Student(Person):
    pass


teacher = Teacher()
teacher.eat()
teacher.drink()

student = Student()
student.eat()
student.drink()

'''
需要吃食物
需要喝水
需要吃食物
需要喝水
'''

3、与继承相关的几个概念

继承:一个类从另一个已有的类获得其成员的相关特性,就叫作继承!

派生:从一个已有的类产生一个新的类,称为派生!

很显然,继承和派生其实就是从不同的方向来描述的相同的概念而已,本质上是一样的!

父类:也叫作基类,就是指已有被继承的类!

子类:也叫作派生类或扩展类

扩展:在子类中增加一些自己特有的特性,就叫作扩展,没有扩展,继承也就没有意义了!

单继承:一个类只能继承自一个其他的类,不能继承多个类,单继承也是大多数面向对象语言的特性!

多继承:一个类同时继承了多个父类


4、单继承

单继承:一个类只能继承自一个其他的类,不能同时继承多个类。这个类会有具有父类的属性和方法。

示例:

# 定义一个共性类(父类)
class Person(object):
    pass
# 定义一个个性类(子类)
class Student(Person):
    pass

案例:比如电脑可以分为两种类型(笔记本电脑、台式电脑)

# 1、定义一个共性类(父类)
class Computer(object):
    def play(self):
        print('可以玩游戏')


class laptops(Computer):
    pass


class desktop(Computer):
    pass


HUAWEI = laptops()
HUAWEI.play()

'''
可以玩游戏
'''

5、单继承特性(多层继承):传递性

在Python继承中,如A类继承了B类,B类又继承了C类。则根据继承的传递性,则A类也会自动继承C类中所有属性和方法(公共)

示例:

class C(object):
    def func(self):
        print('我是C类中的相关方法func')
        
class B(C):
    pass

class A(B):
    pass

a = A()
a.func()

'''
我是C类中的相关方法func
'''

6、多继承

Python语言是少数支持多继承的一门编程语言,所谓的多继承就是允许一个类同时继承多个类的特性。

示例:

class C(object):
    def func1(self):
        print('我是C类中的相关方法func')


class B(object):
    def func2(self):
        print('我是B类中的相关方法func')


class A(C, B):
    pass


a = A()
a.func1()
a.func2()

'''
我是C类中的相关方法func
我是B类中的相关方法func
'''

注意:虽然多继承允许我们同时继承自多个类,但是实际开发中,应尽量避免使用多继承,因为如果两个类中出现了相同的属性和方法就会产生命名冲突。


7、子类扩展:重写父类属性和方法

重写也叫作覆盖,就是当子类成员与父类成员名字相同的时候,从父类继承下来的成员会重新定义!

此时,通过子类实例化出来的对象访问相关成员的时候,真正起作用的是子类中定义的成员!

示例:

class Father(object):
    属性
    方法

class Son(Father):
    父类属性和方法
    自己的属性和方法(如果子类中的属性和方法与父类中的属性或方法同名,则子类中的属性或方法会对父类中同名的属性或方法进行覆盖(重写))

上面单继承例子中Computer的子类laptops和desktop继承了父类的属性和方法,但是我们笔记本电脑类laptops有自己的特点‘可随身携带’,台式电脑类desktop有自己的特点‘性能强悍’,这时我们需要对父类的feature()方法进行重构。

示例:

# 1、定义一个共性类(父类)
class Computer(object):
    def play(self):
        print('可以玩游戏')

    def feature(self):
        print('可以进行计算')

class laptops(Computer):
    def feature(self):
        print('可以进行计算,并且方便携带')


class desktop(Computer):
    def feature(self):
        print('可以进行计算,并且性能强悍')


HUAWEI = laptops()
HUAWEI.feature()

Lenove = desktop()
Lenove.feature()

'''
可以进行计算,并且方便携带
可以进行计算,并且性能强悍
'''

注意:重写父类中的feature方法后,此时父类中的feature方法还在,是不过是在其子类中找不到了。

类方法的调用顺序,当我们在子类中重构父类的方法后,laptops子类的实例先会在自己的类 laptops 中查找该方法,当找不到该方法时才会去父类 Computer中查找对应的方法。


8、super()调用父类属性和方法

super():调用父类属性或方法,完整写法:super(当前类名, self).属性或方法(),在Python3以后版本中,调用父类的属性和方法我们只需要使用super().属性或super().方法名()就可以完成调用了。

示例:

# 1、定义一个共性类(父类)
class Computer(object):
    def play(self):
        print('可以玩游戏')

    def feature(self):
        print('可以进行计算')


class laptops(Computer):
    def feature(self):
        super().feature()
        print('方便携带')


HUAWEI = laptops()
HUAWEI.feature()

'''
可以进行计算
方便携带
'''

9、MRO属性或MRO方法:方法解析顺序

MRO(Method Resolution Order):方法解析顺序,我们可以通过类名.__mro__或类名.mro()获得“类的层次结构”,方法解析顺序也是按照这个“类的层次结构”寻找到。

示例:

# 1、定义一个共性类(父类)
class Computer(object):
    def play(self):
        print('可以玩游戏')

    def feature(self):
        print('可以进行计算')


class laptops(Computer):
    def feature(self):
        super().feature()
        print('方便携带')


print(laptops.__mro__)
print(laptops.mro())

'''
(<class '__main__.laptops'>, <class '__main__.Computer'>, <class 'object'>)
[<class '__main__.laptops'>, <class '__main__.Computer'>, <class 'object'>]
'''

说明:有MRO方法解析顺序可知,在类的继承中,当某个类创建了一个对象时,调用属性或方法,首先在自身类中去寻找,如找到,则直接使用,停止后续的查找。如果未找到,继续向上一级继承的类中去寻找,如找到,则直接使用,没有找到则继续向上寻找…直到object类,这就是Python类继承中,其方法解析顺序。

综上:object类是所有类的基类(应为这个查找关系到object才终止)


二、Python中的多态

1、什么是多态

多态,指的是一类事物有多种形态。比如:同样一个函数在不同的场景下有不同的状态。

定义:多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果。

不同对象 =>使用相同方法=>产生不同的执行结果。

  • 多态以来继承(不是必须的)
  • 子类方法必须要重写父类方法

首先定义一个父类,其可能拥有多个子类对象。当我们调用一个公共方法(接口)时,传递的对象不同,则返回的结果不同。

好处:调用灵活,有了多态,更容易编写出通用的代码,做出通用的编程,以适应需求的不断变化!


2、多态代码实现

多态:可以基于继承也可以不基于继承

示例:

'''
根据多态实现的三个条件,构建一下场景
构建对象对战平台object_play
1 英雄一代战机(战斗力60)与敌军战机(战斗力70)对抗。英雄1代战机失败!
2 卧薪尝胆,英雄二代战机(战斗力80)出场!,战胜敌军战机!
3 对象对战平台object_play, 代码不发生变化的情况下, 完成多次战斗
'''
class HeroFight1(object):
    def power(self):
        return 60


class HeroFight2(HeroFight1):
    # 重写父类方法
    def power(self):
        return 80


class EnemyFight(object):
    # 重写父类方法
    def power(self):
        return 70


# 搭建一个平台,让双方战机PK
def object_play(herofight1: HeroFight1, enemyfight):
    # 注意:此处发生了多态!!!
    if herofight1.power() > enemyfight.power():
        print('英雄战机胜利, 敌机失败')
    else:
        print('英雄战机失败, 敌机胜利')


if __name__ == '__main__':
    # 实例化一代战机、二代战机和敌机
    herofight1 = HeroFight1()
    herofight2 = HeroFight2()
    enemyfight = EnemyFight()
    # 一代战机出场
    object_play(herofight1, enemyfight)
    # 二代战机出场
    object_play(herofight2, enemyfight)

'''
英雄战机失败, 敌机胜利
英雄战机胜利, 敌机失败
'''

3、多态的好处

在不改变框架代码的情况下,通过多态语法轻松的实现模块和模块之间的解耦合;实现了软件系统的可拓展

  • 解耦合:搭建平台def object_play(herofight1: HeroFight1, enemyfight), 相当于任务的调用者;子类、孙子类重写父类的函数,相当于子任务;相当于任务的调用者和任务的编写者进行了解耦合

  • 可拓展:搭建平台def object_play(herofight1: HeroFight1, enemyfight),在不做任何修改的情况下,可以调用后来人写的代码


4、拓展:在Python中还有哪些多态的案例呢?

+ 多态体现

+加号只有一个,但是不同的对象调用+方法,其返回结果不同。

如果加号的两边都是数值类型的数据,则加号代表运算符

如果加号的两边传入的是字符串类型的数据,则加号代表合并操作,返回合并后的字符串

‘a’ + ‘b’ = ‘ab’

如果加号的两边出入序列类型的数据,则加号代表合并操作,返回合并后的序列

[1, 2, 3] + [4, 5, 6] = [1, 2, 3, 4, 5, 6]


三、面向对象其他特性

1、类属性

Python中,属性可以分为实例属性和类属性。

类属性就是 类对象中定义的属性,它被该类的所有实例对象所共有。通常用来记录 与这类相关 的特征,类属性 不会用于记录 具体对象的特征。

在Python中,一切皆对象。类也是一个特殊的对象,我们可以单独为类定义属性。

示例:

class Person(object):
    # 定义类属性
    count = 0
    def __init__(self, name, age):
        self.name = name
        self.age = age

2、类属性代码实现

定义count类属性,用于记录实例化Person类,产生对象的数量。

示例:

class Person(object):
    # 定义类属性count
    count = 0

    # 定义一个__init__魔术方法,用于进行初始化操作
    def __init__(self, name):
        self.name = name
        # 对count类属性进行+1操作,用于记录一共生成了多少个对象
        Person.count += 1


# 实例化对象
p1 = Person('小明')
p2 = Person('小华')
p3 = Person('小红')
# 输出类属性
print(f'一个生成了{Person.count}个实例化对象')

'''
一个生成了3个实例化对象
'''

3、类方法

所谓类方法,指的是类所拥有的方法,并需要使用[装饰器]@classmethod来标识其为类方法

同时一定要注意的是对于类方法的第一个参数必须是类对象,通常以cls作为第一个参数名,格式如下:

@classmethod
def 类方法名(cls):
    ...

调用时,格式如下:

# 方式一:
类名.类方法名()  # 推荐使用
# 方式二:
对象名.类方法名()

示例:

# 1.定义类
class Dog(object):
    __num = 6
    
    # 类方法
    @classmethod
    def eat(cls):
        print(cls.__num)
        print('小狗喜欢吃骨头')

        
# 2.调用类方法
# 方式一:
Dog.eat()
# 方式二:
dog = Dog()
dog.eat()

'''
6
小狗喜欢吃骨头
6
小狗喜欢吃骨头
'''

类方法主要用于操作类属性或类中的其他方法。


4、静态方法

静态方法需要通过装饰器@staticmethod来来标识其为静态方法,且静态方法不需要多定义参数,格式如下:

@staticmethod
def 静态方法名():
    ...

调用时,格式如下:

# 方式一:
类名.静态方法名  # 推荐使用
# 方式二:
对象名.静态方法名

示例:

# 开发一款游戏
class Game(object):
    # 开始游戏,打印游戏功能菜单
    @staticmethod
    def menu():
        print('1、开始游戏')
        print('2、游戏暂停')
        print('3、退出游戏')
    

# 开始游戏、打印菜单
Game.menu()

'''
1、开始游戏
2、游戏暂停
3、退出游戏
'''

<think> 我们正在讨论Python中的面向对象三大特性:封装、继承多态。根据用户要求,我们需要详细解释这三个概念,并结合引用中的Python示例进行说明。注意,引用[1]提到封装是描述现实世界,引用[2]引用[4]展示了继承的传递性方法重写(多态),引用[3]则重点说明了封装的实现(使用双下划线表示私有属性)。 我们将按照以下结构组织内容: 1. 封装:定义、目的、Python中的实现(私有成员) 2. 继承:定义、继承传递性、方法重写(作为多态的基础) 3. 多态:定义、在Python中的体现(重写鸭子类型) 注意:在Python中,多态的实现与其他语言(如Java)不同,它主要依赖于鸭子类型(duck typing)方法重写。 开始编写回答: </think> ### Python面向对象三大特性详解:封装、继承多态 #### 一、封装(Encapsulation) **概念**:将数据(属性)操作数据的方法(行为)绑定在类中,通过访问控制隐藏内部实现细节,仅暴露必要接口。这是程序对现实世界的抽象表达(如"人"类封装姓名、年龄属性行走方法)[^1]。 **Python实现机制**: 1. **私有成员**:双下划线前缀`__`实现属性隐藏 2. **公有接口**:提供方法控制属性访问 ```python class BankAccount: def __init__(self): self.__balance = 0 # 私有属性(实际变为_BankAccount__balance) def deposit(self, amount): if amount > 0: self.__balance += amount # 类内可访问 def get_balance(self): # 公有接口 return self.__balance account = BankAccount() account.deposit(100) print(account.get_balance()) # 输出100 print(account.__balance) # 报错:AttributeError(外部不可直接访问) ``` **设计原则**: - 最小暴露原则:成员变量默认设为私有(`__`前缀) - 接口隔离:通过方法暴露功能,隐藏实现复杂度 - 数据验证:在方法中增加业务逻辑(如存款金额校验) #### 二、继承(Inheritance) **概念**:子类自动获取父类的属性方法,实现代码复用层次化扩展。继承具有传递性:子类继承父类,父类继承祖父类,则子类拥有所有祖先类特性[^4]。 **Python实现机制**: ```mermaid classDiagram Animal <|-- Cat Cat <|-- Jiqimao class Animal { +eat() +drink() +sleep() } class Cat { +yell() } class Jiqimao { +speak() +eat() 重写方法 } ``` **关键特性**: 1. **继承传递性**: ```python class Person: def run(self): return "我可以跑步" class Male(Person): def repair(self): return "我可以修理汽车" class Boy(Male): # 继承Male(间接继承Person) def play(self): return "我可以玩耍" boy = Boy() print(boy.run()) # 输出:我可以跑步(继承自Person) print(boy.repair()) # 输出:我可以修理汽车(继承自Male) ``` 2. **方法重写(Override)**:子类覆盖父类方法实现多态 ```python class Animal: def eat(self): print("吃食物") class Cat(Animal): def eat(self): # 重写父类方法 print("吃鱼") cat = Cat() cat.eat() # 输出"吃鱼"而非"吃食物" ``` #### 三、多态(Polymorphism) **概念**:同一接口在不同对象上呈现不同行为,主要依赖方法重写鸭子类型实现。 **实现方式**: 1. **方法重写(运行时多态)**: ```python class Payment: def pay(self): pass class WechatPay(Payment): def pay(self): # 重写实现 print("微信支付") class Alipay(Payment): def pay(self): # 重写实现 print("支付宝支付") def process_payment(payment_obj): # 统一调用接口 payment_obj.pay() process_payment(WechatPay()) # 输出"微信支付" process_payment(Alipay()) # 输出"支付宝支付" ``` 2. **鸭子类型(编译时多态)**: ```python class Duck: def sound(self): print("嘎嘎嘎") class Dog: def sound(self): # 无需继承相同父类 print("汪汪汪") def make_sound(animal): # 只要实现sound()方法即可 animal.sound() make_sound(Duck()) # 输出"嘎嘎嘎" make_sound(Dog()) # 输出"汪汪汪" ``` #### 四、三大特性协同关系 ```mermaid graph LR A[封装] -->|构建独立类| B[继承] B -->|建立类层次| C[多态] C -->|统一调用接口| A ``` - **封装是基石**:构建高内聚的类单元(如银行账户类) - **继承是延伸**:实现代码复用(如`Boy`复用`Person`功能) - **多态是桥梁**:提供灵活的行为适配(如统一支付接口) > Python通过动态类型鸭子类型机制,使多态实现更加灵活,不强制要求继承关系[^2] --- ### 相关问题 1. Python中通过`__`前缀定义的私有成员真的无法从外部访问吗?其底层实现原理是什么?[^3] 2. 当子类重写父类方法时,如何调用被覆盖的父类方法实现?`super()`函数有哪些使用技巧? 3. 鸭子类型(Duck Typing)与传统的基于继承多态有何本质区别?在什么场景下更适合使用鸭子类型? 4. 如何利用Python的`@property`装饰器实现更安全的封装?请举例说明属性校验场景
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值