【Python基础】面向对象基础和特性

2023-11-12

面向对象基础

定义类

特征 = 属性 行为 = 方法

class 类名:
    def 方法名(self[, 参数列表]):
        pass
创建对象
对象名 = 类名()
  • 对象 = 实例 创建对象 = 实例化对象
  • 由哪一个对象调用的方法,方法内的self 就是哪一个对象的引用;
  • 打印对象和打印self得到的结果是⼀致的,都是当前对象的内存地址;
class Washer:
    def wash(self):
        print(self)
        print("洗衣服")


haier = Washer()
print(haier)
haier.wash()

"""
<__main__.Washer object at 0x00000202A0817430>
<__main__.Washer object at 0x00000202A0817430>
洗衣服
"""
添加和获取对象属性
  • 类外面添加对象属性:对象名.属性名 = 值
  • 类里面添加对象属性:self.属性名 = 值
  • 类外面获取对象属性:对象名.属性名
  • 类里面获取对象属性:self.属性名
# 定义类
class Washer:
    def print_info(self):
        # 类⾥⾯获取实例属性
        print(f"{self.name}洗⾐机的宽度是{self.width}")
        print(f"{self.name}洗⾐机的⾼度是{self.height}")

# 创建对象
haier = Washer()
# 添加实例属性
haier.name = "海尔"
haier.width = 500
haier.height = 800
# 调用实例方法
haier.print_info()
魔法方法
  • __init__:初始化对象
    当使用类名()创建对象时,为对象分配完空间后,自动调用__init__方法;
    改造初始化方法,可以让创建对象更加灵活;
  • __str__ :输出对象信息
    当使⽤print输出对象的时候,默认打印对象的内存地址;
    如果类定义了__str__⽅法,则会打印从该方法中return的数据;
  • __del__ :删除对象时调用
    当一个对象被从内存中销毁前,会自动调用__del__方法;
    如果希望在对象被销毁前,再做一些事情,可以使用该方法;
class Washer:
    def __init__(self, name):
        self.name = name
        print(f"{self.name}洗⾐机来了")

    def __str__(self):
        return f"---{self.name}洗衣机---"

    def __del__(self):
        print(f"{self.name}洗⾐机去了")


haier = Washer("海尔")
print(haier)
# 删除一个对象
del haier

print("---我在哪执行?---")

"""
海尔洗⾐机来了
---海尔洗衣机---
海尔洗⾐机去了
---我在哪执行?---
"""
对象的生命周期
  • 一个对象从调用类名()创建,生命周期开始
  • 一个对象的__del__方法一旦被调用,生命周期结束
  • 在对象的生命周期内,可以访问对象属性,或者让对象调用方法
私有属性和私有方法
  • 应用场景:在实际开发中,对象的某些属性或方法可能只希望在对象的内部被使用,而不希望在外部被访问到;
  • 定义方式:在属性名或方法名前增加两个下划线,私有属性和私有方法不能在外界直接访问;
  • 在Python中并没有真正意义的私有,伪私有
  • 在给属性或方法命名时,实际是对名称做了一些特殊处理_类名 => _类名__名称,使得外界无法访问到;
  • 在日常开发中,不要使用这种方式对象名._类名__属性名/方法名,访问对象的私有属性或私有方法;
class Women:
    def __init__(self, name):
        self.name = name
        self.__age = 18
        
    def __secret(self):
        # 在对象的方法内部,是可以访问对象的私有属性的
        print("%s 的年龄是 %d" % (self.name, self.__age))
    
        
xiaofang = Women("小芳")

# 私有属性,外部不能直接访问
print(xiaofang.__age)
# 私有方法,外部不能直接调用
xiaofang.__secret()

#

# 伪私有属性
print(xiaofang._Women__age)
# 伪私有方法
xiaofang._Women__secret()

面向对象特性

  • 封装根据职责将属性和方法封装到一个抽象的类中
    定义类的准则
  • 继承实现代码的重用,相同的代码不需要重复的编写
    设计类的技巧
  • 多态不同的对象调用相同的方法,产生不同的执行结果
    调用方法的技巧
封装
封装案例演练

需求分析:
1、房子(House)有 户型、总面积 和 家具名称列表:新房子没有任何的家具
2、家具(HouseItem)有 名称 和 占地面积,其中:
① 席梦思(bed)占地 4 平米,② 衣柜(chest)占地 2 平米,③ 餐桌(table)占地 1.5 平米
3、将以上三件家具 添加 到 房子 中
4、打印房子时,要求输出:户型、总面积、剩余面积、家具名称列表
在这里插入图片描述

代码实现:

# 1、创建家具类(HouseItem)
class HouseItem:
    def __init__(self, name, area):
        # 家具名称
        self.name = name
        # 家具占地面积
        self.area = area

    def __str__(self):
        return "【%s 占地 %.2f】" % (self.name, self.area)


# 2、创建房子类(House)
class House:
    def __init__(self, house_type, area):
        # 房子户型
        self.house_type = house_type
        # 房子总面积
        self.area = area
        # 房子剩余面积
        self.free_area = area
        # 家具名称列表
        self.item_list = []

    def __str__(self):
        return ("户型:%s\t总面积:%.2f\n剩余面积:%.2f\t家具:%s"
                % (self.house_type, self.area,
                   self.free_area, self.item_list))

    def add_item(self, item):
        print("准备添加 %s" % item)
        # ①判断家具的面积
        if item.area <= self.free_area:
            # ②将家具的名称添加到列表中
            self.item_list.append(item.name)
            print(f"{item.name}已经成功摆放到房子中了")
            # ③计算剩余面积
            self.free_area -= item.area
        else:
            print(f"{item.name}面积太大,剩余面积不足,无法容纳")


# 3、创建对象
bed = HouseItem("席梦思", 40)
chest = HouseItem("衣柜", 2)
table = HouseItem("餐桌", 20)

my_home = House("两室一厅", 60)

# 4、调用实例方法
print(my_home)
my_home.add_item(bed)
my_home.add_item(chest)
my_home.add_item(table)
print(my_home)

运行结果:

户型:两室一厅 总面积:60.00
剩余面积:60.00 家具:[]
准备添加 【席梦思 占地 40.00】
席梦思已经成功摆放到房子中了
准备添加 【衣柜 占地 2.00】
衣柜已经成功摆放到房子中了
准备添加 【餐桌 占地 20.00】
餐桌面积太大,剩余面积不足,无法容纳
户型:两室一厅 总面积:60.00
剩余面积:18.00 家具:['席梦思', '衣柜']
继承

子类拥有父类的所有方法和属性

class 子类名(父类名):
    pass

子类拥有父类的所有方法和属性
子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发
在这里插入图片描述
Dog类 是 Animal类 的 子类,Animal类 是 Dog类 的 父类,Dog类 从 Animal类 继承
Dog类 是 Animal类 的 派生类,Animal类 是 Dog类 的 基类,Dog类 从 Animal类 派生

继承的传递性
  • C类从B类继承,B类又从A类继承,那么C类就具有B类和A类的所有属性和方法;
  • 子类拥有父类以及父类的父类中封装的所有属性和方法
方法的重写

当父类的方法实现不能满足子类需求时,可对方法进行重写
在这里插入图片描述

重写父类方法有两种情况:

  1. 覆盖父类的方法
    如果在开发中,父类的方法实现和子类的方法实现完全不同,就可以使用覆盖的方式;在子类中重写父类的方法实现,相当于在子类中定义了一个和父类同名的方法并且实现;重写之后运行时,只会调用子类中重写的方法,而不再会调用父类中 封装的方法;
  2. 对父类方法进行扩展
    如果在开发中,子类的方法实现中包含父类的方法实现,父类原本封装的方法实现是子类方法的一部分,就可以使用扩展的方式;在子类中重写父类的方法,在需要的位置使用super().父类方法来调用父类方法的执行,在其他的位置针对子类的需求,编写子类特有的代码实现;
父类的私有属性和私有方法
  • 子类对象不能在自己方法内直接访问父类的私有属性或私有方法;
  • 子类对象可通过父类的公有方法间接访问到私有属性或私有方法;

在这里插入图片描述
B 的对象不能直接访问 __num2 属性
B 的对象不能在 demo 方法内访问 __num2 属性
B 的对象可以在 demo 方法内,调用父类的 test 方法
父类的 test 方法内部,能够访问 __num2 属性和 __test 方法

多继承

子类拥有多个父类且具有所有父类的属性和方法

class 子类名(父类名1, 父类名2):
    pass

使用多继承时若不同父类中存在同名的方法,子类对象在调用方法时,会调用哪一个父类中的方法呢?
在这里插入图片描述
MRO 方法搜索顺序 主要用于在多继承时判断方法、属性的调用路径
Python中针对类提供了一个内置属性 __mro__ 可以查看方法搜索顺序;在搜索方法时,是按照 __mro__ 的输出结果从左至右的顺序查找的;如果在当前类中找到方法,就直接执行不再搜索;如果没有找到,就查找下一个类中是否有,找到就直接执行不再搜索;如果找到最后一个类,还没有找到方法,程序报错;

注意:如果父类之间存在同名的属性或者方法,应该尽量避免使用多继承!

新式类与经典类
  • object是Python为所有对象提供的基类,提供有一些内置的属性和方法,可以使用dir函数查看;新式类:以object为基类的类,推荐使用;经典类:不以object为基类的类,不推荐使用;
  • Python 3.x中定义类时,如果没有指定父类,会默认使用object作为该类的基类;Python 2.x中定义类时,如果没有指定父类,则不会以object作为该类的基类;
  • 新式类和经典类在多继承时会影响到方法的搜索顺序:为了保证编写的代码能够同时在 Python 2.x 和 Python 3.x 运行,今后在定义类时,如果没有父类,建议统一继承自object
多态

不同的子类对象调用相同的父类方法,产生不同的执行结果

以继承和重写父类方法为前提
多态案例演练

需求分析:
1、在Dog类中封装game方法,普通狗只是简单的玩耍
2、定义XiaoTianDog类继承自Dog类,并重写game方法,哮天犬需要在天上玩耍
3、定义Person类,并封装一个和狗玩的方法game_with_dog
在game_with_dog方法内部,直接让狗对象调用game方法
在这里插入图片描述
Person类中只需要让狗对象调用game方法,而不关心具体是什么狗
game方法是在Dog父类中定义的
在程序执行时,传入不同的狗对象实参,就会产生不同的执行效果

代码实现:

class Dog(object):
    def __init__(self, name):
        self.name = name
    def game(self):
        print("%s 蹦蹦跳跳的玩耍" % self.name)

class XiaoTianDog(Dog):
    def game(self):
        print("%s 飞到天上去玩耍" % self.name)

class Person(object):
    def __init__(self, name):
        self.name = name
    def game_with_dog(self, dog):
        print("%s 和 %s 一起快乐的玩耍" % (self.name, dog.name))
        dog.game()


erha = XiaoTianDog("飞天二哈")
xiaoming = Person("小明")
xiaoming.game_with_dog(erha)


'''
小明 和 飞天二哈 一起快乐的玩耍
飞天二哈 飞到天上去玩耍
'''

面向对象其他

实例对象
  1. 设计类
  2. 创建对象 类名()
    在内存中为对象分配空间
    调用__init__方法为对象初始化
  3. 创建对象后,内存中就有一个实实在在的存在,即实例
    创建出来的对象 = 类的实例
    创建对象的动作 = 实例化
    对象的属性 = 实例属性
    对象调用的方法 = 实例方法

在这里插入图片描述
在程序执行时,通过 self. 访问自己的属性或调用自己的方法
每一个对象都有自己独立的内存空间,保存各自不同的属性
多个对象的方法在内存中只有一份,在调用方法时,需将对象的引用传递到方法内部

类对象
  • Python中一切皆为对象,类是一个特殊的对象
  • 通过 class 类名: 定义的类属于类对象
  • 通过 对象名 = 类名() 创建的对象属于实例对象

在这里插入图片描述
在程序运行时,通过 类名. 访问类的属性或调用类的方法
类对象在内存中只有一份,使用一个类可以创建出很多个对象实例
除了封装实例的属性和方法外,类对象也可以拥有自己的属性和方法

  • 实例方法方法内部需要访问实例属性
  • 实例方法内部可以使用类名.访问类属性
  • 类方法方法内部只需要访问类属性
  • 静态方法内部不需要访问实例属性和类属性
类属性
  • 类属性是类对象定义的属性,在class下方使用赋值语句定义;
  • 通过用来记录与这个类相关的属性,类属性不会用于记录具体对象的特征;
  • 要访问类属性的方式(向上查找机制):类名.类属性对象名.类属性(不推荐)
  • 如果使用 对象.类属性 = 值 设置值,只会给对象添加一个属性,而不会影响到类属性的值;
类方法
  • 类方法就是针对类对象定义的方法,需用修饰器@classmethod来标识;
  • 由哪一个类调用的方法,方法内的cls就是哪一个类的引用;
  • 通过类名.调用类方法,调用方法时,不需要传递cls参数;
  • 在类方法内部通过cls.访问类属性或调用其他的类方法;
@classmethod
def 类方法名(cls):
    pass
静态方法
  • 既不需要访问实例属性和调用实例方法
  • 也不需要访问类属性和调用类方法
  • 静态方法需要用修饰器@staticmethod 来标识
  • 通过类名.调用静态方法
@staticmethod
def 静态方法名():
    pass
案例演示

需求分析:
1.设计一个Game类
2.属性:
① 类属性 top_score 记录游戏的历史最高分,② 实例属性 player_name 记录当前游戏的玩家姓名
3.方法:
① 静态方法 show_help 显示游戏帮助信息,② 类方法 show_top_score 显示历史最高分,③ 实例方法 start_game 开始当前玩家的游戏
4.主程序步骤
① 查看帮助信息,② 查看历史最高分,③ 创建游戏对象,开始游戏
在这里插入图片描述

代码实现:

class Game(object):
    # 游戏最高分,类属性
    top_score = 0

    @staticmethod
    def show_help():
        print("帮助信息:让僵尸走进房间")

    @classmethod
    def show_top_score(cls):
        print("游戏最高分是 %d" % cls.top_score)

    def __init__(self, player_name):
        self.player_name = player_name

    def start_game(self):
        print("[%s] 开始游戏..." % self.player_name)
        # 使用类名.修改历史最高分
        Game.top_score = 999


# 1. 查看游戏帮助
Game.show_help()

# 2. 查看游戏最高分
Game.show_top_score()

# 3. 创建游戏对象,开始游戏
game = Game("小明")
game.start_game()

# 4. 游戏结束,查看游戏最高分
Game.show_top_score()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Python基础】面向对象基础和特性 的相关文章

随机推荐

  • C++ 中内存分区总结

    背景 C 中最基本的存储单位是字节 C 中所有的数据都是由对象组成的 每一个对象都包含了一个或多个内存位置 C 中有多种不同类型的内存区域 不同区域存放不同的数据 赋予数据不同的生命周期 程序在执行时将供用户使用内存大致划分为以下区域 常量
  • 激光灯

    激光等中使用的通讯方式 简介 通讯介绍 DMX512通讯 DMX512通讯物理层 DMX512通讯应用层 ILDA通讯 ILDA通讯物理层 DMX512通讯应用层 Art Net 网络通讯 简介 本文作为起始书写的第一篇 但可能不是专栏中的
  • Error : Program type already present: android.support.design.widget.CoordinatorLayout$

    Error Program type already present android support design widget CoordinatorLayout 原因是在页面中使用recyclerView导致的 主要是design和co
  • Cache-Control max-age=0

    http blog csdn net ysdaniel article details 7969766 Cache Control no cache 强制每次请求直接发送给源服务器 而不经过本地缓存版本的校验 这对于需要确认认证应用很有用
  • 第二章 下载AOSP WiFi相关的代码

    第一章 国内下载AOSP最新源码的方法 文章目录 前言 一 需下载的仓库清单 二 下载命令 三 代码仓目录结构 总结 前言 WiFi相关的仓库包括Settings SettingsLib wifi service wpa supplican
  • micropython移植教程_Micropython移植篇——从点亮一个灯开始

    收到论坛申请的 MicroPython入门指南 已经两天了 看到了第四章 没有再往下看了 感觉应该先找个硬件移植 然后再往下看 跟着学习 这样才有意义 好了 先说下移植的过程吧 硬件采用的是STM32F429DISC 具体步骤 第一步 下载
  • Matlab 学习笔记 (部分内容系转载)

    由于要参加数学建模比赛的原因 我需要在不到一周的时间内初步地学习Matlab 因此 我希望把我在学习过程中阅读的资料记录下来 方便跟我一样需要在较短时间内速成Matlab的同学 基本上我记录的东西都是从网上的资料总结而来 所以这篇文章更偏向
  • MySQL读写分离实战

    1 MySQL读写分离概念 MYSQL读写分离的原理其实就是让Master数据库处理事务性增加 删除 修改 更新操作 create insert update delete 而让Slave数据库处理查询 select 操作 MySQL读写分
  • Java基础--------集合框架

    参考http blog csdn net zhongkelee article details 46801449 点击打开链接 以此为模板 自己做了整理 修改 目录 一 概念 二 集合框架的体系 2 1 Collection接口 2 1 1
  • 三维人脸重建(二)——Python生成ply文件

    目录 引言 一 ply格式模型介绍 二 代码 注 引言 本文主要以做坐标点为例 我们知道python对数据的处理主要是以numpy的形式 一般三维空间坐标的矩阵在python中为 x1 y1 z1 x2 y2 z2 xn yn zn 然后可
  • Java中的栈区和堆区问题(关于数组)

    Java中创建的局部变量等是存放在栈区的 而数组是存放在堆区的 那些new出来的对象也大多存放于堆区 栈区的空间往往不大 而堆区空间就会大很多 这里我们创建一个数组 如果在idea中打印a 会得到一串符号 这个是数组在堆区首元素的地址 代表
  • 数据结构 图 part2

    文章目录 图的遍历 深度优先遍历 DFS 遍历步骤 邻接矩阵的存储 邻接表的存储 广度优先遍历 BFS 遍历步骤 非连通图的遍历 连通分量 如何遍历 生成树 图的遍历 深度优先遍历 DFS 遍历步骤 在访问图中某一起始顶点v后 由v出发 访
  • 测试开发——用例篇(如何设计一个测试用例,设计测试用例的一些具体方法)

    目录 一 测试用例的基本要素 二 设计测试用例的万能公式 在没有需求文档的情况下 1 水杯的测试用例 2 一个网站的登录测试用例 三 基于需求进行测试用例的设计 四 测试用例的具体设计方法 根据需求 1 等价类 2 边界问题 3 判定表 因
  • 阿里云云解析DNS各种概念深度剖析

    摘要 本文所设计概念有 主机记录 www 记录类型 A记录 CNAME记录 TXT记录 解析路线 isp 网络服务提供商 记录值 TTL time to live 缓存生存时间 地方DNS DNSPod 场景描述 域名解析有一个 记录数 和
  • KEIL5中点击build会全编译的解决方法

    今天在笔记本上调试STM32时 发现每次点击build 总是会对工程内所有文件进行编译 相当于是rebuild的功能 开始以为是keil5版本的问题 经过网上查找并亲自测试 现得出解决办法 在Option中C C 一栏内 添加路径包含工程内
  • 联想rd540服务器怎么装系统,联想RD540加显卡BIOS设置

    开机按F1进入BIOS设置界面 然后进入CONFIG子界面 找到Display这个子项 然后回车进入 这个是设置显示输入和显卡的地方 里面有三个项目 Boot Display Device 启动时使用的显示装置 1 保持默认Thinkpad
  • RabbitMQ修改数据目录MNESIA数据目录

    RabbitMQ修改数据目录MNESIA数据目录 一 什么情况要调整数据目录 1 1 磁盘空间不足 1 2 磁盘性能瓶颈 1 3 迁移集群的备份还原 1 4 数据分离 二 MNESIA简介 三 操作步骤 四 其他问题 4 1 重启失败 一
  • Python习题答案

    1 多选题 程序设计语言包括 和 执行两种方式 正确答案 AB A 编译 B 解释 C 脚本 D 编写 2 单选题 机器语言是一种 语言 正确答案 A A 二进制 B 八进制 C 十进制 D 十六进制 3 单选题 是将源代码转换成目标代码的
  • sqli靶场通关之less9

    sqli less9 时间盲注 结合burpsuite 1 不返回报错信息页面 无法进行基于报错信息的盲注 2 页面不存在true和false两种不同的页面 无法进行对比也就无法进行布尔盲注 一般来说 在页面没有任何回显和错误信息提示的时候
  • 【Python基础】面向对象基础和特性

    Python面向对象 面向对象基础 定义类 创建对象 添加和获取对象属性 魔法方法 对象的生命周期 私有属性和私有方法 面向对象特性 封装 封装案例演练 继承 继承的传递性 方法的重写 父类的私有属性和私有方法 多继承 新式类与经典类 多态