首页 > 编程语言 >Python入门-面相对象——class(类)、封装、继承、多态、类型注解

Python入门-面相对象——class(类)、封装、继承、多态、类型注解

时间:2024-10-15 22:48:27浏览次数:3  
标签:__ Python 子类 self 多态 cake 父类 class make

面向对象

面向对象就是设计一个类,基于创建对象,并使用创建出来的类完成具体的工作

面向对象的三大特性:封装继承多态

面向对象基本概述:
    属性: 名词, 用来描述事物的外在特征的, 例如: 姓名, 性别, 年龄, 身高, 体重...
    行为: 动词, 表示事物能够做什么, 例如: 学习, 吃, 睡...
    类: 抽象的概念, 看不见, 摸不着.  类 = 属性 + 行为
    对象: 类的具体体现, 实现.

定义类的格式:
    class 类名:
        # 属性, 就和以前定义变量一样.
        # 行为, 就和以前定义函数一样, 只不过第一个形参要写self

如何使用类中的成员:
    1. 创建该类的对象.
        对象名 = 类名()
    2. 通过 对象名. 的方式来调用.
        对象名.属性
        对象名.行为()

1. class(类)

初识对象

使用对象组织数据:先 创建类(class),类名加括号便是创建对象,最后对象属性赋值

# 设计一个类(类比生活,登记表)
class PersonTable:
    name = None

# 设计对象(打印登记表)
t1 = PersonTable()

# 对象属性进行赋值
t1.name = 'bob'

# 获取对象中记录的信息
print(t1.name)

类的成员

class是关键字,表示要定义类了
类的属性(数据),即定义在类中的变量(成员变量)
类的行为(函数),即定义在类中的函数(成员方法)

定义在类外面的函数叫做函数,类内部的函数叫做方法

# 成员方法的定义语法
def 方法名(self, 形参1, ..., 形参N):
    方法体

方法定义中 self 必须填写,用来表示类对象自身的意思,谁调用self, self就是谁。
当我们使用类对象调用方法时,self会自动被python传入,在方法内部想要访问类的成员变量,必须使用 self

类和对象

类只是一种程序内的 ’设计图纸‘ ,需要基于图纸生产实体(对象),才能正常工作,称为:面向对象编程

魔法方法

魔法方法在创建类对象(构造类)的时候:
(1) 会自动执行
(2)将传入参数自动传递给构造方法使用

其他内置方法(魔术方法)

_ _init__是python类内置的方法之一,内置的类方法,各有各自特殊的方法,这些内置方法称之为:魔术方法

常用的魔法方法:
    __init__()  在创建对象的时候, 会被自动调用, 一般用于给对象初始化一些属性值.     即:  对象名 = 类名()  就会自动调用该魔法方法.
    __str__()   当输出语句直接打印对象的时候, 会自动调用该魔法方法, 默认打印的是地址值, 无意义, 一般会改为: 打印该对象的各个属性值.
    __del__()   当手动删除对象时 或者 文件执行结束后, 该函数会被自动调用.

可以理解为:
    init魔法方法:       创建1个对象 = 调用一次
    str魔法方法:        打印一次对象 = 调用一次
    del魔法方法:        只要删除1个该类的对象 = 调用一次


# 小于、大于符号比较
__lt__

# 小于等于、大于等于符号比较
__le__

# ==符号比较
__eq__


2. 封装

封装的概念:将现实世界事物在类中描述为 属性和方法,即为封装

类中的部分属性和行为不对外公开,称为私有成员,类对象无法访问私有成员,但类中的其他成员可以访问私有成员

封装介绍:
    概述:
        封装指的是 隐藏对象的属性 和 实现细节, 仅对外提供公共的访问方式.
    问1: 怎么隐藏 对象的属性 和 实现细节(函数)?
    答: 通过 私有化解决.

    问2: 公共的访问方式是什么?
    答: get_xxx(), set_xxx()函数.

    问3: get_xxx()和set_xxx()函数 必须成对出现吗?
    答: 不一定, 看需求, 如果只获取值就用 get_xxx(), 如果只设置值就用 set_xxx(). 如果需求不明确, 建议都写.

    问4: 封装指的就是 私有, 这句话对吗?
    答: 不对, 因为我们常用的函数也是封装的一种体现.

    好处:
        1. 提高代码的安全性.        通过 私有化 实现的.
        2. 提高代码的复用性.        通过 函数 实现的.
    弊端:
        代码量增量了, 封装的代码量会变多.
        这里的代码量增加指的是:  私有化以后, 就要提供公共的访问方式, 私有化内容越多, 公共的访问方式就越多, 代码量就越多.

私有化介绍:
    格式:
        __属性名       # 注意: 这里是 两个_
        __函数名()
    特点:
        只能在本类中直接访问, 外界无法直接调用.
        
私有化方法.   即: 父类的私有化方法, 也需要提供1个公共的访问方式, 让子类来访问.

问: 什么时候使用私有化呢?
答: 父类的成员不想被子类直接继承(或者重写, 修改等), 但是还想给子类用, 就可以考虑用私有化.

以下是一个简单的案例

# 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):
    # 演示用, 在子类中 恶意的修改 父类的函数内容. 通过 方法重写 实现.
    # def make_cake(self):
    #     print('加入调料: 砒霜')
    #     print('加入调料: 鹤顶红')
    #     print('加入调料: 含笑半步癫')
    #     print('加入调料: 一日断肠散')
    #     # 调用父类的方法.
    #     super().make_cake()

    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. 继承

继承的概念:一个类继承另外一个类的成员变量和方法
单继承: 一个类继承另一个类,
多继承:一个类继承多个类,按照顺序从左向右一次继承
多继承中如果 父类有同名的属性或方法 ,先继承的优先级高于后继承

pass:普通的占位语句,用来保证属性、方法或类定义的完整性,表示无内容,空的意思(不写新的属性和方法,只是为了语法不报错)

复写:子类继承父类的成员属性和方法后,如不满意,可复写,即:在子类用重新定义同名的属性或方法

:只可以在子类内部调用父类的同名成员,子类的实体类对象调用默认是子类复写后的

"""
继承相关概述:
    概述:
        实际开发中, 我们发现好多类中的部分内容是相似的, 或者相同的, 每次写很麻烦, 针对于这种情况, 我们可以把这些相似(想同)的部分抽取出来,
        单独的放到1个类中(父类), 然后让那多个类(子类) 和这个类产生关系, 这个关系就叫: 继承.
    可以理解为:
        子承父业,   Python中的继承,  子类 => 继承父类的 属性, 行为.
    格式:
        class 子类名(父类名):
            pass
    好处:
        1. 提高代码的复用性.
        2. 提高代码的可维护性.
    弊端:
        耦合性增强了.   父类"不好"的内容, 子类想没有都不行.
    叫法:
        子类: 也叫 派生类, 扩展类.
        父类: 也叫 基类, 超类.
    object:
        所有的类都直接或者间接继承自object, 它是所有类的父类, 也叫: 顶级类.

"""

# 案例: 父类有默认性别男, 爱好散步行走, 定义子类继承父类, 看是否可以访问这些属性 和 行为.
# 1. 定义父类.
class Father:
    # 1.1 定义父类的属性.
    def __init__(self):
        self.gender = '男'

    # 1.2 定义父类的行为
    def walk(self):
        print('饭后走一走, 能活九十九!')

# 2. 定义子类, 继承自父类.
class Son(Father):
    pass

# 在main中测试
if __name__ == '__main__':
    # 3. 创建子类的对象.
    s = Son()
    # 4. 尝试打印 s对象的 属性 和 行为
    print(f'性别: {s.gender}')
    s.walk()
    
# 一旦复写父类成员,调用类对象时会调用复写后的新成员,需要使用特殊方式调用
1. 父类名.成员变量   父类名.成员方法(self)
2. super().成员变量   super().成员方法()

3.1 继承-多继承
  1. Python中支持多继承写法, 即: 1个类可以有多个父类, 写法为: class 子类名(父类名1, 父类名2…)
  2. 多继承关系中, 子类可以继承所有父类的属性和行为. 前提: 父类的私有成员除外.
  3. 多继承关系中, 多个父类如果有重名属性或者方法时, 子类会优先使用第1个父类(即: 最前边的父类)的该成员.
  4. 上述的继承关系, 我们可以通过 Python内置的 mro属性 或者 mro()方法来查看.
    mro: Method Resolution Order, 即: 方法的解析顺序(调用顺序)

3.2 继承-方法重写

概述:
子类出现和父类重名的属性, 方法时, 会覆盖父类中的成员, 这种写法就称之为: 重写, 也叫: 覆盖.

注意:
重写一般特指: 方法重写.

应用场景:
当子类需要沿袭父类的功能, 而功能主体又有自己额外需求的时候, 就可以考虑使用方法重写了.

"""
子类有和父类重名的属性和方法时, 优先使用 子类的成员.     就近原则.

问: 重写后, 子类如何访问父类的成员呢?
答:
    格式1: 父类名.父类方法名(self)
    格式2: super().父类方法()

super关键字介绍:
    概述:
        它类似于self, 只不过: self代表本类当前对象的引用.   super代表本类对象 父类的引用.
    可以理解为:
        self = 自己, super = 父类
    作用:
        初始化父类成员, 实现 在子类中访问父类成员的.
    细节:
        1. super()在多继承关系中, 只能初始化第1个父类的成员, 所以: super()更适用于 单继承环境.
        2. 多继承关系中, 如果想实现精准初始化(操作)某个父类的成员, 可以通过 父类名.父类方法名(self)
        3. 在单继承关系中, 用 super() 可以简化代码.
"""

# 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 = '[黑马AI煎饼果子配方]'

    # 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_old_cake(), 表示: 父类的摊煎饼果子配方.
    def make_old_cake(self):
        # 前提(细节): 需要重新初始化一下父类的 属性.
        super().__init__()

        # 调用 父类的#make_cake()
        # Master.make_cake(self)    # 格式1: 父类名.父类方法名(self)
        super().make_cake()         # 格式2: super().父类方法名()


# 在main函数中测试
if __name__ == '__main__':
    # 4. 创建子类的对象
    p = Prentice()
    # 5. 尝试打印 p对象的 属性 和 行为
    print(f'属性: {p.kongfu}')    # 独创煎饼果子配方
    p.make_cake()                # 独创煎饼果子配方
    print('-' * 21)

    # 6. 调用父类的 煎饼果子配方
    p.make_old_cake()            # 黑马AI


3.3 多层继承

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

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

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

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

    # 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()        # 黑马AI

4. 多态

概念:多态指的是:多种状态,即同样的行为(函数),传入不同的 对象,得到不同的状态

多态常作用在继承关系上。函数(方法)形参声明接收父类对象,实际传入父类的对象进行工作,即:以父类做定义声明,以子类做实际工作,用以获得同一行为,不同状态

抽象类

父类用来确定有哪些方法,具体的方法实现由子类自行决定,这种写法叫做抽象类(接口),含有抽象方法的类称为抽象类,方法体是空实现的(pass)称为抽象方法

抽象类的作用:多用于做顶层设计,以便子类做具体实现,也是对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法,并配合多态使用,获得不同的工作状态


"""
多态:
    概述:
        多态指的是同一个事物在不同时刻, 不同场景下表现出来的不同形态, 状态.
    可以理解为:
        Python中的多态: 同一个函数 接收不同的参数 会有不同的结果.
        现实生活中的多态: 一杯水, 高温 => 气体,  常温 => 液体,  低温 => 固体.
    前提条件:
        1. 要有继承关系.      # 扩展: 没有继承关系也行, 因为Python是弱类型的, 对数据的类型限定不严格, 可以称之为 => 伪多态.
        2. 要有方法重写, 否则无意义.
        3. 要有父类引用指向子类对象.
    多态的好处:
        提高代码的可维护性. 即: 同样的一个函数, 未来需求变化了, 我们传入不同的参数即可, 无需修改源码, 既有不同的结果.
        扩展: 开发原则, 对修改关闭, 对扩展开放.   大白话: 需求变化了, 不能该源码, 尽量加代码.
    多态的弊端:
        不知道传入的是哪一个具体的子类, 所以无法直接访问子类的特有成员.
    多态在实际开发中的应用场景:
        父类型作为方法形参的数据类型, 这样可以接受其任意的子类对象, 实现传入什么子类对象, 就调用其对应的功能.
        
        
需求:
    构建对象对战平台object_play,
    1. 英雄一代战机(战斗力60)与敌军战机(战斗力70)对抗。英雄1代战机失败!
    2. 卧薪尝胆,英雄二代战机(战斗力80)出场!,战胜敌军战机!
    3. 对象对战平台object_play, 代码不发生变化的情况下, 完成多次战斗

分析流程:
    抽象战机类 HeroFighter  AdvHeroFighter;敌机EnemyFighter;
    构建对象战斗平台, 使用多态实现
"""

# 1. 构建 1代 英雄机.
class HeroFighter(object):
    def power(self):
        return 60   # 战斗力: 60

# 2. 构建 2代 英雄机.
class AdvHeroFighter(HeroFighter):
    def power(self):
        return 80   # 战斗力: 80

# 3. 构建 敌机.
class EnemyFighter(object):
    def power(self):
        return 70   # 战斗力: 70

# 4. 搭建对战平台, 即: 通用的函数, 接收不同的参数, 效果不同, 但是函数还是那个函数.
def object_play(hf:HeroFighter, ef:EnemyFighter):
    # 具体的战斗过程
    if hf.power() > ef.power():
        print('英雄机获得胜利!')
    elif hf.power() < ef.power():
        print('敌机惨胜!')
    else:
        print('平局!')


# 5. 在main函数中测试.
if __name__ == '__main__':
    # 5.1 创建 各种战机.
    hf1 = HeroFighter()     # 1代英雄机
    hf2 = AdvHeroFighter()  # 2代英雄机
    ef = EnemyFighter()     # 敌机

    # 5.2 具体的对战过程.
    # Pythong中的多态: 同一个函数 接受不同的参数 实现不同的效果 => 多态
    object_play(hf1, ef)    # 1代英雄机 和 敌机
    print('-' * 21)
    object_play(hf2, ef)    # 2代英雄机 和 敌机


类型注解

类型注解分为:

  • 变量的类型注解
  • 函数(方法)形参列表的类型注解
  • 返回值的类型注解

类型注解只要帮助第三方IDE工具对代码进行类型推断,协助做代码提示,帮助开发者自身对变量类型注解(备注),并不会真正的对类型做验证和判断,类型注解仅仅是提示性的,不是决定性的

Union可以定义联合类型注解

# 变量类型注解基本语法
格式1: 变量:类型
格式2: 在注释中:# type:类型

# 函数(方法)形参进行类型注解语法
def 函数方法名(形参名: 类型, ... ):
    pass

# 函数(方法)返回值进行类型注解
def 函数方法名(形参名: 类型, ... ) -> 返回值类型 :
    pass

# Union 类型注释语法:Union[类型, ..., 类型]
from typing import Union
a: list[Union[str, int]] = [1, 2, 'itheima']
b: dict[str, Union[str, int]] = {'a': 'Jay', 'age': 19}

标签:__,Python,子类,self,多态,cake,父类,class,make
From: https://blog.csdn.net/m0_74893204/article/details/142965846

相关文章

  • python+flask计算机毕业设计在线教育平台(程序+开题+论文)
    文件加密系统的设计与实现tp835本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展,教育领域正经历着前所未有的变革。在线教育平台作为互联网+教育的重要产物,已经逐......
  • python+flask计算机毕业设计中电科海信院培训考试系统的设计与实现(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和企业培训需求的日益增长,构建一个高效、便捷的培训考试系统已成为众多企业和研究机构的重要任务。中电科海信院作......
  • python+flask计算机毕业设计智慧点餐系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,智能化、便捷化的服务已成为现代生活的重要组成部分。在餐饮行业,传统的点餐方式已难以满足顾客日益增长的个性化需......
  • python+flask计算机毕业设计跃动小商品在线交易系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展和电子商务的蓬勃兴起,线上交易已成为人们日常生活不可或缺的一部分。小商品市场作为经济体系中的重要组成部分,其......
  • 【攻防世界】Web_python_template_injection
    Web_python_template_injection:python模板漏洞python的flask模板注入的题思路比较固定,Jinja2模板引擎中,{{}}是变量包裹标识符。{{}}并不仅仅可以传递变量,还可以执行一些简单的表达式。1.先判断是否存在注入{{config}}2.获取基本类:{{''.__class__.__mro__}}.__class......
  • 【PAT_Python解 带全部测试点】1068 万绿丛中一点红
    原题链接:PTA|程序设计类实验辅助教学平台测试点0:独一无二测试点1: NotUnique测试点2:NotExist测试点3:独一无二       点在边缘(相邻数值不足8个)45207000000000400000070答案:(4,3):4测试点5:点在边缘(相邻数值不足8个)4520000......
  • python类与魔法方法
    文章目录1.类的创建与实例化2.类的魔法方法3.类属性与函数4.类的继承与改写4.1继承属性与函数4.2多重多继承4.3super()函数(减少反复继承初始化)4.4继承中mro与函数调用顺序4.5父类的重写与调用5.多态、类方法6.模块导入6.1导入文件6.2导包路径问题7.prope......
  • 基于yolov8、yolov5的烟雾检测系统(含UI界面、训练好的模型、Python代码、数据集)
    项目介绍项目中所用到的算法模型和数据集等信息如下:算法模型:  yolov8、yolov8+SE注意力机制或yolov5、yolov5+SE注意力机制,直接提供最少两个训练好的模型。模型十分重要,因为有些同学的电脑没有GPU,无法自行训练。数据集:  网上下载的数据集,格式都已......
  • python实现了通过摄像头检测手部动作,根据手指数量的不同映射为特定的视频控制操作
    importcv2#导入OpenCV库,用于图像处理importmediapipeasmp#导入MediaPipe库,用于手部检测等fromseleniumimportwebdriver#导入selenium库fromselenium.webdriver.common.keysimportKeysfromselenium.webdriver.common.byimportByfromselenium.webdrive......
  • Python学习流水账Day5——有关Python中的函数
    文章目录前言一、Python中的函数1.内置函数2.定义一个函数调用函数为函数设置参数实参形参给函数设置多个形参默认形参函数的返回值函数的变量局部变量全局变量3.匿名函数4.递归函数总结前言简单的python复习第五天:不是用来教学的,上班没劲,主打一个本科毕业没竞......