python进阶篇-day02-面向对象高级

2024-08-31 04:28

本文主要是介绍python进阶篇-day02-面向对象高级,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

day02面向对象高级

 

 

定义类的方法

class Student:
class Student():
class Student(object):  object => 父类名, object为所有类的父类, 顶级类

 

 

 

一. 继承

单继承

介绍

概述

实际开发中, 我们发现好多类中的部分内容是相似的, 或者相同的, 每次写很麻烦, 针对于这种情况, 我们可以把这些相似(想同)的部分抽取出来,单独的放到1个类中(父类), 然后让那多个类(子类) 和这个类产生关系, 这个关系就叫: 继承.

子承父业, Python中的继承, 子类 => 继承父类的 属性, 行为.

格式

class 子类名(父类名):pass

好处

  1. 提高代码的复用性.

  2. 提高代码的可维护性.

弊端

耦合性增强了. 父类"不好"的内容, 子类想没有都不行.耦合: 指的是类与类之间的关系.

别名

子类: 也叫 派生类, 扩展类.父类: 也叫 基类, 超类.

细节

所有的类都直接或者间接继承自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

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

代码

# 1. 创建1个师傅类, 充当父类.
class Master(object):# 1.1 定义父类的 属性.def __init__(self):self.kongfu = '[古法煎饼果子配方]'
​# 1.2 定义父类的 行为, 表示: 摊煎饼.def make_cake(self):print(f'使用 {self.kongfu} 制作煎饼果子')
​
​
# 2. 定义徒弟类, 继承自师傅类.
class Prentice(Master):pass
​
​
# 在main函数中测试
if __name__ == '__main__':# 3. 创建子类的对象p = Prentice()# 4. 尝试打印 p对象的 属性 和 行为print(f'从父类继承的属性: {p.kongfu}')p.make_cake()  # 从父类继承来的行为.

 

 

多继承

介绍

  1. Python中支持多继承写法, 即: 1个类可以有多个父类, 写法为: class 子类名(父类名1, 父类名2...)

  2. 多继承关系中, 子类可以继承所有父类的属性和行为. 前提: 父类的私有成员除外(__方法或属性).

  3. 多继承关系中, 多个父类如果有重名属性或者方法时, 子类会优先使用第1个父类(即: 最前边的父类)的该成员.

  4. 上述的继承关系, 我们可以通过 Python内置的 mro属性 或者 mro()方法来查看.mro: => Method Resolution Order, 即: 方法的解析顺序(调用顺序)

案例

故事2

小明是个爱学习的好孩子,想学习更多的摊煎饼果子技术,于是,在百度搜索学校,报班来培训学习摊煎饼果子技术。

代码

# 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):pass
​
​
# 在main函数中测试
if __name__ == '__main__':# 4. 创建子类的对象p = Prentice()# 5. 尝试打印 p对象的 属性 和 行为print(f'从父类继承的属性: {p.kongfu}')p.make_cake()  # 从父类继承来的行为.print('-' * 21)
​# 6. 演示方法的解析顺序, 即: MRO, 看看方法优先会从哪些类中找.print(Prentice.__mro__)     # 输出: Prentice >  School > Master > object, 封装成: 元组print(Prentice.mro())       # 输出: Prentice >  School > Master > object, 封装成: 列表

 

 

方法重写

介绍

概述: 子类出现和父类重名的属性, 方法时, 会覆盖父类中的成员, 这种写法就称之为: 重写, 也叫: 覆盖.注意: 重写一般特指: 方法重写.应用场景: 当子类需要沿袭父类的功能, 而功能主体又有自己额外需求的时候, 就可以考虑使用方法重写了.

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

  1. 重写后, 子类如何访问父类的成员呢

    格式1: 父类名.父类方法名(self)格式2: super().父类方法()

案例

故事3

小明掌握了老师傅和的技术后, 子级潜心钻研出一套自己的独门配方的全新煎饼果子配方.

代码

# 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} 制作煎饼果子')
​
​
# 在main函数中测试
if __name__ == '__main__':# 4. 创建子类的对象p = Prentice()# 5. 尝试打印 p对象的 属性 和 行为print(f'属性: {p.kongfu}')p.make_cake()print('-' * 21)
​# 6. 演示方法的解析顺序, 即: MRO, 看看方法优先会从哪些类中找.print(Prentice.__mro__)     # 输出: Prentice >  School > Master > object, 封装成: 元组print(Prentice.mro())       # 输出: Prentice >  School > Master > object, 封装成: 列表

重写后调用父类

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

故事4

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

代码

# 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)
​
# 在main函数中测试
if __name__ == '__main__':# 4. 创建子类的对象p = Prentice()# 5. 尝试打印 p对象的 属性 和 行为print(f'属性: {p.kongfu}')    # 独创煎饼果子配方p.make_cake()                # 独创煎饼果子配方print('-' * 21)
​# 6. 调用父类 Master类的 古法煎饼果子配方p.make_master_cake()         # 古法print('-' * 21)
​# 7. 调用父类 School类的 古法煎饼果子配方p.make_school_cake()         # AI

super().父类方法()

介绍

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

案例

# 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().父类方法名()

多层继承

介绍

概述: 实际开发中, 类与类之间是可以多层继承的,

例如: 类A继承类B, 类B继承类C, 这就是: 多层继承.例如: A => 继承B => 继承C => 继承object

案例

故事5

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

代码

# 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 => objectpass
​
​
# 在main函数中测试
if __name__ == '__main__':# 4. 创建 徒孙类 的对象ts = TuSun()
​# 5. 调用父类的成员.print(f'属性: {ts.kongfu}')  # 独创煎饼果子配方ts.make_cake()  # 独创煎饼果子配方
​ts.make_master_cake()  # 古法ts.make_school_cake()  # AI

 

 

 

 

二. 封装

封装介绍

概述:

封装指的是 隐藏对象的属性 和 实现细节, 仅对外提供公共的访问方式.

问题

问1: 怎么隐藏 对象的属性 和 实现细节(函数)?答: 通过 私有化解决.

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

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

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

好处:

1. 提高代码的安全性. 通过 私有化 实现的. 2. 提高代码的复用性. 通过 函数 实现的.

弊端:

代码量增量了, 封装的代码量会变多. 这里的代码量增加指的是: 私有化以后, 就要提供公共的访问方式, 私有化内容越多, 公共的访问方式就越多, 代码量就越多.

私有化介绍

格式

__属性名__函数名()

特点

只能再本类中直接访问, 外界无法直接调用

私有属性案例

故事6

小明把技术传承给徒弟的同时,不想把自己的私房钱($500000)继承给徒弟,这时就要为钱这个属性设置私有权限。

代码

# 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):# 可以在这里对 money属性做判断, 但是没必要. 因为Python属于后端代码, 这里的钱肯定是前端传过来的, 而传过来的数据已经经过了前端的校验.# 换言之, 这里如果校验就属于 二次校验了.  实际开发中, 重要字段会做二次校验, 否者可以不做校验.# if money > 0:#     self.__money = money# else:#     self.__money = 0self.__money = money
​# 1.3 行为def make_cake(self):print(f'采用 {self.kongfu} 制作煎饼果子!')# 验证: 私有成员, 在本类中是可以直接访问的.print(f'私房钱为: {self.__money}')
​
# 2. 定义徒孙类, 继承自徒弟类.
class TuSun(Prentice):pass
​
# 在main函数中测试调用
if __name__ == '__main__':# 3. 创建徒孙类对象.ts = TuSun()# 4. 尝试访问父类的成员.# 父类的公共的 属性 和 行为.print(f'父类的属性: {ts.kongfu}')ts.make_cake()print("-" * 21)# 父类的 私有的 属性.# print(f'父类的私有属性: {ts.money}')   # 报错, AttributeError# print(f'父类的私有属性: {ts.__money}')   # 报错, AttributeErrorprint(f'父类的私有属性, 通过 公共的方式访问: {ts.get_money()}')
​# 通过父类的公共方式, 修改 父类的私有属性.ts.set_money(10)
​print(f'父类的私有属性, 通过 公共的方式访问: {ts.get_money()}')

私有方法案例

父类的私有化方法, 也需要提供1个公共的访问方式, 让子类来访问.

故事7

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

代码

# 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()

 

 

三. 多态

多态指的是同一个事物在不同时刻, 不同场景下表现出来的不同形态, 状态.

介绍

前提条件

  1. 要有继承关系.

    扩展: 没有继承关系也行, 因为Python是弱类型的, 对数据的类型限定不严格, 可以称之为 => 伪多态.

  2. 要有方法重写, 否则无意义.

  3. 要有父类引用指向子类对象.

好处

提高代码的可维护性.

即: 同样的一个函数, 未来需求变化了, 我们传入不同的参数即可, 无需修改源码, 既有不同的结果.

扩展: 开发原则, 对修改关闭, 对扩展开放.

大白话: 需求变化了, 不能该源码, 尽量加代码.

弊端

不知道传入的是哪一个具体的子类, 所以无法直接访问子类的特有成员.

应用场景

父类型作为方法形参的数据类型, 这样可以接受其任意的子类对象, 实现传入什么子类对象, 就调用其对应的功能.

案例1:动物

# 1. 定义父类, 动物类, 有个speak()函数.
class Animal(object):def speak(self):pass
​
# 2. 定义子类, 狗类, 继承自动物类, 重写Animal#speak()函数.
class Dog(Animal):# 重写父类的speak()函数def speak(self):print('汪汪汪!')
​
# 3. 定义子类, 猫类, 继承自动物类, 重写Animal#speak()函数.
class Cat(Animal):def speak(self):print('喵喵喵!')
​def catch_mouse(self):print('猫会抓老鼠!')
​
# 4.假设需求变化, 增加了 猴子类.
class Monkey(Animal):def speak(self):print('桀桀桀!')
​
# 验证Python是伪多态, 即: print_animal()函数, 不传入Animal的子类的对象, 也行.
class Phone:def speak(self):print('手机叫一次, 你要唱一首歌!')
​
# 5. 定义函数, 接收Animal类型, 调用speak()函数.
# def print_animal(an):   # an:Animal = Dog(),   an:Animal = Cat(), 父类引用指向子类对象.
def print_animal(an: Animal):   # an:Animal = Dog(),   an:Animal = Cat(), 父类引用指向子类对象.an.speak()# an.catch_mouse() 不能访问子类的 特有成员.
​
​
# 6. 在main函数中测试
if __name__ == '__main__':# 6.1 创建猫对象, 狗对象.cat = Cat()dog = Dog()mon = Monkey()
​# 6.2 调用print_animal()函数.# 发现: 同一个函数, 接受不同的对象, 实现效果不一样 => 多态.print_animal(cat)print('-' * 21)print_animal(dog)print('-' * 21)print_animal(mon)print('-' * 21)
​# 7. 调用print_animal()函数, 传入 非Animal类的子类.phone = Phone()print_animal(phone)

案例2:飞机

需求

构建对象对战平台object_play,

  1. 英雄一代战机(战斗力60)与敌军战机(战斗力70)对抗。英雄1代战机失败!

  2. 卧薪尝胆,英雄二代战机(战斗力80)出场!,战胜敌军战机!

  3. 对象对战平台object_play, 代码不发生变化的情况下, 完成多次战斗

代码

# 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代英雄机 和 敌机

抽象类

介绍

概述: 有抽象方法的类就叫 抽象类, 也可以称之为: 接口.抽象方法: 没有方法体的方法, 叫: 抽象方法, 即: 方法体是用 pass 来编写的.作用/目的: 抽象类: 一般充当父类, 用于制定: 标准. 子类: 普通类 继承抽象类, 重写抽象方法, 提供具体的实现即可.

案例:空调

需求

创建AC类(空调类), 表示空调的标准, 热风, 冷风, 左右摆风...不同的子类来实现这些功能. 例如: 格力, 美的...

代码

# 1. 定义AC类(空调类, 抽象类), 表示: 空调的标准.
class AC(object):# 1.1 制冷, 抽象方法(没有方法体的方法)def cool_wind(self):pass
​# 1.2 热风def hot_wind(self):pass
​# 1.3 左右摆风def swing_l_r(self):pass
​
# 2. 定义Gree类(格力空调类), 继承: AC类.
class Gree(AC):# 2.1 重写 AC#cool_wind 方法def cool_wind(self):print('格力空调 核心制冷技术 制作冷风')
​# 2.2 重写 AC#hot_wind 方法def hot_wind(self):print('格力空调 核心制热技术 制作热风')
​# 2.3 重写 AC#swing_l_r 方法def swing_l_r(self):print('格力空调 左右摆风!')
​
# 3. 定义Media类(美的空调类), 继承: AC类.
class Media(AC):# 3.1 重写 AC#cool_wind 方法def cool_wind(self):print('美的空调 核心制冷技术 制作冷风')
​# 3.2 重写 AC#hot_wind 方法def hot_wind(self):print('美的空调 核心制热技术 制作热风')
​# 3.3 重写 AC#swing_l_r 方法def swing_l_r(self):print('美的空调 左右摆风!')
​
# 定义函数, 测试空调的性能.
def my_ac(ac: AC):ac.cool_wind()ac.hot_wind()ac.swing_l_r()
​
# 4. 在main函数中测试.
if __name__ == '__main__':# 非多态方式# 4.1 测试 格力空调.g = Gree()g.cool_wind()g.hot_wind()g.swing_l_r()print('-' * 21)
​# 4.2 测试 美的空调.m = Media()m.cool_wind()m.hot_wind()m.swing_l_r()print('-' * 21)
​# 5. 多态方式.my_ac(g)print('-' * 21)my_ac(m)

 

 

四. 面向对象其他特性

类属性和对象属性

名词解释

对象属性

概述: 属于 对象的属性, 即: 每个对象都有, 且A对象的属性值修改了 不会影响 B对象的属性值. 类似于: 你个人的钱包.

定义格式: 类外: 对象名.属性名 = 属性值 类内: 写到 init魔法方法中, self.属性名 = 属性值

调用格式: 类外: 对象名.属性名 类内: self.属性名

类属性

概述: 属于 类的属性, 即: 可以被 该类下所有的对象所共享. 即: 无论是谁修改了这个变量的值, 之后大家用的都是修改后的.

定义格式: 定义在类中, 方法外的位置, 写法和以前我们写变量的格式 一样.

调用格式: 方式1: 类名.属性名 方式2: 对象名.属性名 可以这样写, 但是不推荐.

细节: 修改类属性必须通过 类名.属性名 = 属性值 的方式来修改, 不能通过 对象名.属性名 = 属性值的方式来修改. 因为: 前者是在修改 类属性的值, 后者是在 给对象新增1个属性.

技巧

简单记忆, 类变量的获取 和 修改都通过 类名. 的方式来操作, 肯定不会报错.

演示

# 1. 定义学生类.
class Student:# 1.1 定义 类属性(类变量).teacher_name = '哥'
​# 1.2 对象属性, 类内 设置.def __init__(self):self.name = '张三'    # 对象属性, 该类的每个对象都有.
​
# 在main函数中测试.
if __name__ == '__main__':# 2. 创建学生类对象.s1 = Student()s2 = Student()
​# 3. 对象属性, 在类外 设置 对象属性.s1.name = '李四's1.age = 21     # 只有s1对象有.
​# 4. 对象属性, 在类外 获取 对象属性.print(f'类外获取对象属性值: {s1.age}')       # 21print(f'类外获取对象属性值: {s1.name}')      # 李四print(f'类外获取对象属性值: {s2.name}')      # 张三print("-" * 21)
​# 5. 在类外, 访问类属性# 方式1: 类名. 的方式print(Student.teacher_name)     # 哥# 方式2: 对象名. 的方式, 可以, 但是不推荐.print(s1.teacher_name)          print(s2.teacher_name)          print("-" * 21)
​# 6. 修改类属性的值.Student.teacher_name = '老师'     # 可以修改 类属性值s1.teacher_name = '老师'          # 不是在修改类变量的值, 而是在给s1对象新增1个属性值.
​# 7. 重新打印 类属性的值.# 方式1: 类名. 的方式print(Student.teacher_name)  # 老师# 方式2: 对象名. 的方式, 可以, 但是不推荐.print(s1.teacher_name)  # 老师print(s2.teacher_name)  # 老师

 

类方法和静态方法

名词解释

类方法

概述: 它表示属于类的方法, 可以被所有的对象共享.细节: 1. 必须用装饰器 @classmethod 来修饰. 2. 第一个参数必须是 cls, 表示: 当前类的 引用, 即: 等价于 类名. 的形式 3. 类方法可以被 对象名. 或者 类名. 的方式来调用, 推荐使用 后者.

静态方法

概述: 它表示属于 所有对象所共享 的方法, 可以被所有的对象共享.细节: 1. 必须用装饰器 @staticmethod 来修饰. 2. 无参数要求, 根据需求来即可, 可传可不传. 3. 静态方法可以被 对象名. 或者 类名. 的方式来调用, 推荐使用 后者.

区别

  1. 用的装饰器不同.类方法: @classmethod静态方法: @staticmethod

  2. 是否必须要传 第1个参数.类方法: 必须传cls参数, 表示 当前类的引用.静态方法: 根据需求来即可, 可传可不传.

 

演示

# 1. 定义学生类.
class Student:name = 'AI'   # 类属性
​def __init__(self):self.age = 18     # 对象属性
​def method(self):print('我是method函数, 普通方法')
​@staticmethoddef method2():print('我是method2方法, 我是静态方法')print(f'调用类属性: {Student.name}')
​@classmethoddef method3(cls):   # cls来源于 class单词# self = 本类对象的引用, 类似于 对象名.# cls = 本类的引用, 类似于: 类名.print('我是method3方法, 我是类方法')print(f'cls表示类属性, 内容为: {cls}')  # <class '__main__.Student'>print(f'调用类属性: {cls.name}')
​
# 在main函数中测试.
if __name__ == '__main__':# 2. 创建对象.s1 = Student()
​# 3. 访问 静态方法Student.method2()       # 方式1: 类名.s1.method2()            # 方式2: 对象名.print('-' * 21)
​# 4. 访问 类方法Student.method3()      # 方式1: 类名.s1.method3()           # 方式2: 对象名.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

这篇关于python进阶篇-day02-面向对象高级的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1122887

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

nudepy,一个有趣的 Python 库!

更多资料获取 📚 个人网站:ipengtao.com 大家好,今天为大家分享一个有趣的 Python 库 - nudepy。 Github地址:https://github.com/hhatto/nude.py 在图像处理和计算机视觉应用中,检测图像中的不适当内容(例如裸露图像)是一个重要的任务。nudepy 是一个基于 Python 的库,专门用于检测图像中的不适当内容。该

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip

HTML提交表单给python

python 代码 from flask import Flask, request, render_template, redirect, url_forapp = Flask(__name__)@app.route('/')def form():# 渲染表单页面return render_template('./index.html')@app.route('/submit_form',

Python QT实现A-star寻路算法

目录 1、界面使用方法 2、注意事项 3、补充说明 用Qt5搭建一个图形化测试寻路算法的测试环境。 1、界面使用方法 设定起点: 鼠标左键双击,设定红色的起点。左键双击设定起点,用红色标记。 设定终点: 鼠标右键双击,设定蓝色的终点。右键双击设定终点,用蓝色标记。 设置障碍点: 鼠标左键或者右键按着不放,拖动可以设置黑色的障碍点。按住左键或右键并拖动,设置一系列黑色障碍点

Python:豆瓣电影商业数据分析-爬取全数据【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】

**爬取豆瓣电影信息,分析近年电影行业的发展情况** 本文是完整的数据分析展现,代码有完整版,包含豆瓣电影爬取的具体方式【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】   最近MBA在学习《商业数据分析》,大实训作业给了数据要进行数据分析,所以先拿豆瓣电影练练手,网络上爬取豆瓣电影TOP250较多,但对于豆瓣电影全数据的爬取教程很少,所以我自己做一版。 目