Python进阶————面向对象高级



前言

  • 接下来我们学习Python中的继承、封装、多态以及其他特性

一、继承

  • 面向对象中的继承: 指的是多个类之间的所属关系,即子类默认继承父类的属性和方法。

1.1. 单继承

语法

class 类名(父类名):
	代码
	...

一个摊煎饼的老师傅[master],在煎饼果子界摸爬滚打多年,研发了一套精湛的摊煎饼技术, 师父要把这套技术传授给他的唯一的最得意的徒弟[apprentice]。[初始化、无参]

# 1.定义师傅类
class Master(object):
    # 1.1 属性
    def __init__(self):
        self.kofu = '[传统方法]'

    # 1.2 方法
    def make_cake(self):
        print(f'使用{self.kofu}摊煎饼')


# 2.定义徒弟类  继承自Master
class Tudi(Master):
    pass

# 3.实例化
xiaoming = Tudi()         
print(xiaoming.kofu)	  # [传统方法]
xiaoming.make_cake()	  # 使用[传统方法]摊煎饼

1.2. 多继承

  • 多继承就是:一个类同时继承了多个父类。

语法

class 类名(父类名1,父类名2,...):  # 多个父类
	代码
	...

小明是个爱学习的好孩子,想学习更多的摊煎饼果子技术,于是,在百度搜索到小吃学校[school],学习摊煎饼果子技术。

# 1.定义师傅类
class Master(object):
    # 1.1 属性
    def __init__(self):
        self.kofu = '[传统方法]'

    # 1.2 方法
    def make_cake(self):
        print(f'使用{self.kofu}摊煎饼')


# 2.定义学校类
class School(object):
    # 1.1 属性
    def __init__(self):
        self.kofu = '[学院派方法煎饼]'

    # 1.2 方法
    def make_cake(self):
        print(f'使用{self.kofu}摊煎饼')


# 3.定义徒弟类
class Tudi(School, Master):
    pass


# 3.实例化
xiaoming = Tudi()
print(xiaoming.kofu)    # [学院派方法煎饼]
xiaoming.make_cake()    # 使用[学院派方法煎饼]摊煎饼

注意:当一个类有多个父类时,默认使用第一个父类的同名属性和方法。

1.3. 方法重写

  • 重写也叫作覆盖,就是当子类属性或方法与父类的属性或方法名字相同的时候,从父类继承下来的成员可以重新定义!

xiaoming 掌握了老师傅的技术后,自己潜心钻研出一套自己的独门配方的全新摊煎饼果子技术。

# 1.定义师傅类
class Master(object):
    # 1.1 属性
    def __init__(self):
        self.kofu = '[传统方法]'

    # 1.2 方法
    def make_cake(self):
        print(f'使用{self.kofu}摊煎饼')


# 2.定义学校类
class School(object):
    # 1.1 属性
    def __init__(self):
        self.kofu = '[学院派方法]'

    # 1.2 方法
    def make_cake(self):
        print(f'使用{self.kofu}摊煎饼')


# 3.定义徒弟类
class Tudi(School,Master):
    # 1.1 属性
    def __init__(self):
        self.kofu = '[xiaoming独创技术]'
    # 1.2 方法
    def make_cake(self):
        print(f'使用{self.kofu}摊煎饼')


# 3.实例化
xiaoming = Tudi()
print(xiaoming.kofu)   # [xiaoming独创技术]
xiaoming.make_cake()   # 使用[xiaoming独创技术]摊煎饼

当父类中跟子类中有同名方法的时候,子类可以重写父类方法,子类对象调用该方法的时候,优先使用自己的,用完再用父类的

1.4. 子类调用父类方法

  • 子类中仍想要保留父类的行为,则需要在子类中调用父类方法可以使用的以下两个方法:

1.4.1 父类名.父类方法名()

使用该方法的时候父类名.父类方法名(self) 括号中必须要有self

很多顾客都希望能吃到徒弟做出的有自己独立品牌的煎饼果子,也有学校配方技术的煎饼果子味道。

# 1.定义师傅类
class Master(object):
    # 1.1 属性
    def __init__(self):
        self.kofu = '[传统方法]'

    # 1.2 方法
    def make_cake(self):
        print(f'使用{self.kofu}摊煎饼')


# 2.定义学校类
class School(object):
    # 1.1 属性
    def __init__(self):
        self.kofu = '[学院派方法]'

    # 1.2 方法
    def make_cake(self):
        print(f'使用{self.kofu}摊煎饼')


# 3.定义徒弟类
class Tudi(School,Master):
    # 1.1 属性
    def __init__(self):
        self.kofu = '[独创技术]'
    # 1.2 方法
    def make_cake(self):
        print(f'使用{self.kofu}摊煎饼')

    # 1.3 使用老师傅的技术
    def master_make_cake(self):
        Master.__init__(self)
        Master.make_cake(self)

    # 1.4 使用学校技术
    def school_make_cake(self):
        School.__init__(self)
        School.make_cake(self)


# 3.实例化
xiaoming = Tudi()
print(xiaoming.kofu)         # [独创技术]
xiaoming.make_cake()	     # 使用[独创技术]摊煎饼
xiaoming.master_make_cake()  # 使用[传统方法]摊煎饼
xiaoming.school_make_cake()	 # 使用[学院派方法]摊煎饼

1.4.2 super().父类方法名()

使用该方法的时候,super后边必须加括号,且 父类方法名括号中啥也不能有

很多顾客都希望能吃到徒弟做出的有自己独立品牌的煎饼果子,也有学校配方技术的煎饼果子味道。

# 1.定义师傅类
class Master(object):
    # 1.1 属性
    def __init__(self):
        self.kofu = '[传统方法]'

    # 1.2 方法
    def make_cake(self):
        print(f'使用{self.kofu}摊煎饼')


# 2.定义学校类
class School(object):
    # 1.1 属性
    def __init__(self):
        self.kofu = '[学院派方法]'

    # 1.2 方法
    def make_cake(self):
        print(f'使用{self.kofu}摊煎饼')


# 3.定义徒弟类
class Tudi(School,Master):
    # 1.1 属性
    def __init__(self):
        self.kofu = '[独创技术]'
    # 1.2 方法
    def make_cake(self):
        print(f'使用{self.kofu}摊煎饼')

    # 1.3 使用老师傅的技术
    def master_make_cake(self):
    	# 必须重新初始化父类的属性
        Master.__init__(self)
        super().make_cake()

    # 1.4 使用学校技术
    def school_make_cake(self):
        # 必须重新初始化父类的属性
        School.__init__(self)
        super().make_cake()


# 3.实例化
xiaoming = Tudi()
print(xiaoming.kofu)         # [独创技术]
xiaoming.make_cake()	     # 使用[独创技术]摊煎饼
xiaoming.master_make_cake()  # 使用[传统方法]摊煎饼
xiaoming.school_make_cake()	 # 使用[学院派方法]摊煎饼

1.5. 多层继承

"""
多层继承介绍:
    概述:
        实际开发中, 类与类之间是可以多层继承的, 例如: 类A继承类B, 类B继承类C, 这就是: 多层继承.
    例如:
        A => 继承B => 继承C => 继承object
"""

N年后,小明老了,想要把“有自己的独立品牌,也有学院配方技术的煎饼果子味道”的所有技术传授给自己的徒弟。

# 1. 创建1个师傅类, 充当父类.
class Master(object):
    # 1.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    # 1.2 定义父类的 行为, 表示: 摊煎饼.
    def make_cake(self):
        print(f'使用 {self.kongfu} 制作煎饼果子')

# 2. 创建1个师傅类, 充当父类.
class School(object):
    # 2.1 定义父类的 属性.
    def __init__(self):
        self.kongfu = '[学院派煎饼果子配方]'

    # 2.2 定义父类的 行为, 表示: 摊煎饼.
    def make_cake(self):
        print(f'使用 {self.kongfu} 制作煎饼果子')

# 3. 定义徒弟类, 继承自师傅类.
class Prentice(School, Master):
    # 3.1 定义本类(子类)的 属性.
    def __init__(self):
        self.kongfu = '[独创煎饼果子配方]'

    # 3.2 定义本类(子类)的 行为, 表示: 摊煎饼.
    def make_cake(self):        # 子类出现和父类重名且一模一样的函数, 称之为: 方法重写.
        print(f'使用 {self.kongfu} 制作煎饼果子')

    # 3.3 定义函数 make_master_cake(), 表示: 古法摊煎饼果子配方.
    def make_master_cake(self):
        # 前提(细节): 需要重新初始化一下父类的 属性.
        Master.__init__(self)
        # 调用Master#make_cake()
        Master.make_cake(self)

    # 3.4 定义函数 make_school_cake(), 表示: 黑马AI摊煎饼果子配方.
    def make_school_cake(self):
        # 前提(细节): 需要重新初始化一下父类的 属性.
        School.__init__(self)
        # 调用School#make_cake()
        School.make_cake(self)

# 4. 定义徒孙类, 继承: 徒弟类.
class TuSun(Prentice):      # 继承关系:  TuSun => Prentice => School, Master => object
    pass

# 在main函数中测试
if __name__ == '__main__':
    # 4. 创建 徒孙类 的对象
    ts = TuSun()

    # 5. 调用父类的成员.
    print(f'属性: {ts.kongfu}')  # 属性: [独创煎饼果子配方]
    ts.make_cake()               # 使用 [独创煎饼果子配方] 制作煎饼果子
    ts.make_master_cake()        # 使用 [古法煎饼果子配方] 制作煎饼果子
    ts.make_school_cake()        # 使用 [学院派煎饼果子配方] 制作煎饼果子

二、封装

  • 在软件编程中,将属性和方法书写到类的里面的操作即为封装,封装可以为属性和方法添加私有权限。

2.1. 私有属性

  • 在Python中,可以为属性设置私有权限,即设置某个属性不继承给子类。

  • 设置私有权限的方式:在属性名前面加上两个下划线 __,

格式

"""
self.__属性名

当设置了属性为私有属性后,那么我们只能在本类中通过self. 的方法来访问该属性

如果在类外想要访问私有属性的话,必须通过公共方法才行
"""

代码如下(示例):

class Prentice(object):
    # 1.1 属性
    def __init__(self):
        self.kongfu = '[独创的煎饼果子配方]'
        # 私有的属性.
        self.__money = 500000         # 这个才是私有化的写法.

    # 1.2 对外提供公共的访问方式, 可以实现: 获取私有的变量, 以及给变量设置值.
    # 获取值.
    def get_money(self):
        return self.__money

    # 设置值
    def set_money(self, money):
        # 可以在这里对 money属性做判断, 但是没必要. 因为Python属于后端代码, 这里的钱肯定是前端传过来的, 而传过来的数据已经经过了前端的校验.
        # 换言之, 这里如果校验就属于 二次校验了.  实际开发中, 重要字段会做二次校验, 否者可以不做校验.
        # if money > 0:
        #     self.__money = money
        # else:
        #     self.__money = 0
        self.__money = money



# 2. 定义徒孙类, 继承自徒弟类.
class TuSun(Prentice):
    pass

# 在main函数中测试调用
if __name__ == '__main__':
    # 3. 创建徒孙类对象.
    ts = TuSun()
    # 4. 尝试访问父类的成员.
    # 父类的公共的 属性
    print(f'父类的属性: {ts.kongfu}') # 父类的属性: [独创的煎饼果子配方]

    print(f'父类的私有属性, 通过 公共的方式访问: {ts.get_money()}')  # 父类的私有属性, 通过 公共的方式访问: 500000
    
    # 通过父类的公共方式, 修改 父类的私有属性.
    ts.set_money(10)
    print(f'父类的私有属性, 通过 公共的方式访问: {ts.get_money()}')  # 父类的私有属性, 通过 公共的方式访问: 10

2.2. 私有方法

  • 在Python中,可以为方法设置私有权限,即设置某个方法不继承给子类。
  • 设置私有权限的方式:在方法名前面加上两个下划线 __

格式

"""
def __方法名(self):
     ...

当设置了属性为私有属性后,那么我们只能在本类中通过self. 的方法来访问该属性

如果在类外想要访问私有属性的话,必须通过公共方法才行
"""

小明把煎饼果子技术传承给徒弟的同时,不想把自己的独创配方制作过程继承给徒弟,这时就要为制作独创配方这个方法设置私有权限。

# 1. 定义徒弟类, 有自己的属性 和 行为.
class Prentice(object):
    # 1.1 属性
    def __init__(self):
        self.kongfu = '[独创的煎饼果子配方]'
        # 私有的属性.
        # self.__money__ = 500000     # 这个不是私有, 就是变量名叫: __money__
        self.__money = 500000         # 这个才是私有化的写法.

    # 1.2 对外提供公共的访问方式, 可以实现: 获取私有的变量, 以及给变量设置值.
    # 获取值.
    def get_money(self):
        return self.__money

    # 设置值
    def set_money(self, money):
        self.__money = money

    # 1.3 行为
    def __make_cake(self):
        print(f'采用 {self.kongfu} 制作煎饼果子!')
        # 验证: 私有成员, 在本类中是可以直接访问的.
        print(f'私房钱为: {self.__money}')

    # 针对于父类的私有方法, 提供公共的访问方式(在其内部调用 私有化的方法即可)
    def my_make(self):
        # 调用私有化方法 __make_cake()
        self.__make_cake()

# 2. 定义徒孙类, 继承自徒弟类.
class TuSun(Prentice):

    pass

# 在main函数中测试调用
if __name__ == '__main__':
    # 3. 创建徒孙类对象.
    ts = TuSun()

    # 4. 尝试访问父类的成员.
    # 4.1 父类的 私有的 属性.
    print(f'父类的私有属性, 通过 公共的方式访问: {ts.get_money()}')
    # 通过父类的公共方式, 修改 父类的私有属性.
    ts.set_money(10)
    print(f'父类的私有属性, 通过 公共的方式访问: {ts.get_money()}')
    print('-' * 21)

    # 4.2 父类的 私有的 方法(行为).
    # ts.__make_cake()        # AttributeError, 父类私有成员(方法), 子类无法直接访问.
    # ts.make_cake()
    ts.my_make()

三、多态

3.1. 多态的条件

"""
1、有继承 (定义父类、定义子类,子类继承父类)
2、函数重写 (子类重写父类的函数)
3、父类引用指向子类对象 (子类对象传给父类对象调用者)
"""

3.2. 多态的定义

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

代码演示如下

class Animal(object):
    def speak(self):
        print("animal 嗯嗯 ")
        pass


class Dog(Animal):
    def speak(self):
        print('汪汪汪')


class Cat(Animal):
    def speak(self):
        print('喵喵喵')


# def make_noise(animal):
def make_noise(animal:Animal):
    animal.speak()

if __name__ == '__main__':
    mydog = Dog()
    mycat = Cat()
    animal =  Animal()

    make_noise(mydog)     # 汪汪汪
    # make_noise(mycat)   # 喵喵喵
    # make_noise(animal)   # animal 嗯嗯
    pass

四、面向对象的其他特性

4.1. 对象属性

"""
对于属性,调用时有两种方式,如下:
	1、 self.对象属性名  # 类内部
	
	2、 对象名.对象属性名   # 类外部
"""

4.2. 类属性

"""
所谓类属性,指的就是类所拥有的属性,它被共享于整个类中(即都可以直接调用),格式如下:
		1、 类名.类属性名    # 推荐使用

		2、 对象名.类属性名

"""

4.3. 类方法

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

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

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


# 调用时,格式如下:

	1、 类名.类方法名()    # 推荐使用

	2、 对象名.类方法名()

类方法一般和类属性配合使用,尤其是使用私有类属性时。

4.4. 静态方法

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

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

# 调用时,格式如下:
	1、 类名.静态方法名    # 推荐使用

	2、 对象名.静态方法名

功能不变的时候使用静态方法


总结

  • 以上就是面向对象的封装、继承、多态的定义与代码演示。
  • 20
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值