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、退出游戏
'''

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值