08. 面向对象编程(二)

news2025/1/13 2:33:14

目录

1、前言

2、多重继承

2.1、潜在的问题

3、@Property

4、@staticmethod

5、运算符重载

5.1、加法运算符 + 的重载

5.2、字符串表示运算符 str() 的重载

5.3、索引运算符 [] 的重载

6、小结


1、前言

上一篇文章中,我们介绍了面向对象编程的类和实例,以及三大基本特性。今天我们继续来了解面向对象编程的其他知识。

2、多重继承

多重继承是面向对象编程中的一个概念,它允许一个类同时继承自多个父类。这使得子类可以继承多个父类的属性和方法。在Python中,多重继承是支持的,但需要小心使用,因为它可能引起一些设计上的复杂性和潜在的问题。

多重继承的场景:举个例子,我们现在可能会拥有多种角色,比如程序员(Programmer)以及老父亲(Father)。那么Python中我们可能定义两个类:

# 老父亲类
class Father:
    pass

# 程序员类
class Programmer:
    pass

同时,两个不同的类拥有一个相同的方法(eat)和各自不同的方法:老父亲拥有泡奶粉的方法,程序员需要加班改bug的方法。代码示例:

# 老父亲类
class Father:

    # 老父亲需要泡奶粉的动作
    def soak_milk(self):
        print("我是一位老父亲,加班到家后要给娃泡奶粉")

    # 老父亲也要吃饭
    def eat(self):
        print("老父亲要吃饭,吃面条")


# 程序员类
class Programmer:

    # 程序员要加班改bug
    def fix_bug(self):
        print("我是一位程序猿,需要加班改bug")

    # 程序员也要吃饭
    def eat(self):
        print("程序员要吃饭,吃快餐")

最后,我同时拥有这两个角色,那么创建一个我的类,继承了Father和Programmer,之后创建出来的实例就同时拥有了老父亲泡奶粉的能力,以及程序员加班改bug的能力。完整示例代码:

# 创建一个我的类,多重继承Father和Programmer
class Me(Father, Programmer):
    pass

# 创建一个我的实例
me = Me()
# 我要吃饭
me.eat()
# 老父亲泡奶粉
me.soak_milk()
# 程序员改bug
me.fix_bug()

执行结果:

从上述代码中可以看出,多重继承的语法为class 类名(父类1, 父类2...)。如果继承的多个父类中有相同的方法,那么最先执行最左继承的父类。什么?你问我怎么知道的?我猜的!!!来看我猜的对不对,Python提供了一个特殊的方法__mro__来查看类的方法解析顺序。

在多重继承中,Python 使用 C3 线性化算法来确定方法的调用顺序,这被称为方法解析顺序(Method Resolution Order,简称MRO)。MRO 定义了从多个父类中继承方法时的顺序,它是基于 C3 算法生成的线性列表。

查看结果:

先解析Me类,之后是Father,再Programmer。诚不欺客,没骗人吧!

2.1、潜在的问题

尽管多重继承提供了一定的灵活性,但也容易导致一些设计上的复杂性和潜在的问题,例如:

  • 菱形继承问题: 当一个子类继承自两个有共同父类的类时,可能会出现方法冲突的问题。Python 的 MRO 算法通常能够解决这个问题,但在复杂的继承结构中,需要小心设计以避免混淆。
  • 代码可读性:多重继承可能导致代码可读性降低,因为需要追踪多个父类的方法和属性。
  • 耦合性: 过度使用多重继承可能导致类之间的高度耦合,降低了代码的灵活性和可维护性。

3、@Property

@property 是 Python 中用于将方法转换为只读属性的装饰器。通过使用 @property 装饰器,你可以定义一个方法,使之在调用时表现得像一个属性一样。这有助于隐藏类的内部实现细节,提高代码的可读性。正如上一篇中提到受保护成员的访问控制时,除了使用公开方法访问外,还可以此装饰器进行访问。

class Girl:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self._weight = 90   # 女孩子的体重当然是秘密了

    def get_weight(self):
        return self._weight

girl = Girl("小花", 20)
# 访问方式1
print(f"{girl.name}今年{girl.age}岁,体重{girl._weight}公斤")
# 访问方式2
print(f"{girl.name}今年{girl.age}岁,体重{girl.get_weight()}公斤")

上面代码是前面介绍到的访问方式,除了这两个以外,还可以使用@Property。代码改造一下:

class Girl:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self._weight = 90  # 女孩子的体重当然是秘密了

    def get_weight(self):
        return self._weight


    # @Property注解装饰的,是被视为只读的属性
    @property
    def weight(self):
        return self._weight


girl = Girl("小花", 20)
print(f"{girl.name}今年{girl.age}岁,体重{girl.weight}公斤")

也是可以访问的,当我们调用girl.weight时,实际上并不是直接访问属性,而是调用get_weight()方法。使用@Property只是简化了get_weight()的调用方式。

但是值得注意的是@Property注释的属性会被视为只读属性,如果此时你试图修改它,那么Python解释器会给你抛出异常,告诉你他没有setter方法。

当然,如果我们已添加了@Property后,还可以使用“@属性名称.setter"方式来定义属性的setter方法。

class Girl:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self._weight = 90

    def get_weight(self):
        return self._weight


    # @Property注解装饰的,是被视为只读的属性
    @property
    def weight(self):
        return self._weight

    # 添加   @属性名称.setter   表示给该属性添加了setter方法,该setter方法允许你修改该变量的值
    @weight.setter
    def weight(self, val):
        self._weight = val


girl = Girl("小花", 20)
print(f"{girl.name}今年{girl.age}岁,体重{girl.weight}公斤")
girl.weight = 200
print(f"{girl.name}今年{girl.age}岁,体重{girl.weight}公斤")

这时候,我们运行程序就不会报错了:

4、@staticmethod

@staticmethod 是 Python 中用于定义静态方法的装饰器。静态方法是类中的方法,与类的实例无关,因此它不会访问或修改实例的状态。静态方法通常用于执行与类相关的操作,而不需要访问实例的属性。

class MyClass:
    @staticmethod
    def static_method_with_decorator():
        return "I am a static method with decorator"

    def static_method_without_decorator():
        return "I am a static method without decorator"

# 通过类名调用带有装饰器的静态方法
result1 = MyClass.static_method_with_decorator()
print(result1)  # 输出: I am a static method with decorator

# 通过类名调用没有装饰器的静态方法(不推荐)
result2 = MyClass.static_method_without_decorator()
print(result2)  # 输出: I am a static method without decorator

运行结果:

但是你会发现,其实加不加@staticmethod都允许用类名来访问静态方法,那么既然如此为什么要加上这个注解呢?其实,在 Python 中,加不加 @staticmethod 装饰器影响的是对方法的理解和类的设计风格。从功能上来说,不加 @staticmethod 也可以正常工作,因为 Python 允许通过类名直接调用类的方法。

然而,使用 @staticmethod 装饰器有一些优点:

  • 清晰性:@staticmethod 装饰器明确地表明某个方法是静态方法,提高了代码的可读性。读者可以立即看到这个方法是与类相关但与实例无关的。
  • 一致性:在类中使用 @staticmethod 保持了方法定义的一致性,使得在查看类的方法时更容易识别哪些方法是静态的。
  • IDE支持: 使用 @staticmethod 可以让一些集成开发环境(IDE)更好地支持代码提示和文档生成。

5、运算符重载

运算符重载是指在类中定义特殊方法,使得该类的实例对象可以支持一些内建运算符(如+、-、*等)的操作。通过重载运算符,我们可以定义自定义的行为,使得类对象可以与运算符一样被操作。

在Python中,运算符重载是通过特殊方法来实现的,这些方法以双下划线开头和结尾,例如 __add__、__sub__、__mul__等。以下是一些常用的运算符重载方法。

5.1、加法运算符 + 的重载

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        if isinstance(other, Point):
            return Point(self.x + other.x, self.y + other.y)
        else:
            raise TypeError("Unsupported operand type")

p1 = Point(1, 2)
p2 = Point(3, 4)
result = p1 + p2
print(result.x, result.y)  # 输出: 4 6

5.2、字符串表示运算符 str() 的重载

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f"Point({self.x}, {self.y})"

p = Point(1, 2)
print(str(p))  # 输出: Point(1, 2)

5.3、索引运算符 [] 的重载

class Vector:
    def __init__(self, values):
        self.values = values

    def __getitem__(self, index):
        return self.values[index]

v = Vector([1, 2, 3, 4, 5])
print(v[2])  # 输出: 3

运算符重载为类提供了更自然和直观的使用方式,使得类的实例对象可以像内建类型一样参与各种操作。然而,需要小心不要滥用运算符重载,以避免使代码变得难以理解和维护。

6、小结

面向对象的内容远不及如此,这里只是简单介绍了最最常用的部分内容,帮助学习和入门。更多的面向对象使用还是需要结合实际项目,才会更加深入和彻底的学习掌握。今天就到这吧,一起学习,一起加油!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1401476.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安规电容的知识

1、常见安规电容有哪些? 一般我们所说的安规电容也就有两种,一种就是X安规电容(X1/X2/X3安规电容),还有一种是Y电容(最常见的是Y1和Y2安规电容)。 2、x电容的位置 火线零线间的是X电容。x电容用…

保证缓存一致性的常用套路

缓存更新的套路 看到好些人在写更新缓存数据代码时,先删除缓存,然后再更新数据库,而后续的操作会把数据再装载的缓存中。然而,这个是逻辑是错误的。试想,两个并发操作,一个是更新操作,另一个是查…

傲梅轻松备份-备份rocky9,并还原备份

傲梅分区助手磁盘备份功能免费;备份iso镜像不支持linux,好像只能备份window;且备份镜像收费功能,永久授权99; 概述: 1)新建备份U盘 2)新建虚拟机,配置虚拟机&#xff…

C++将信息输入到文件内

第一步检查文件是否打开&#xff0c;用到头文件&#xff1a; #include <fstream> #include <sstream> 文件打开的函数为 file.isopen() 信息输入到文件应该为 file << "" << value; 注意是file<< 如图 定义file ofstream f…

Dell戴尔XPS 8930笔记本电脑原装Win10系统 恢复出厂预装OEM系统

链接&#xff1a;https://pan.baidu.com/s/1eaTQeX-LnPJwWt3fBJD8lg?pwdajy2 提取码&#xff1a;ajy2 原厂系统自带所有驱动、出厂主题壁纸、系统属性联机支持标志、系统属性专属LOGO标志、Office办公软件、MyDell等预装程序 文件格式&#xff1a;esd/wim/swm 安装方式&am…

FFT加窗和频谱泄露

所谓加窗&#xff0c;目的就是针对非整周期采样得到的非自窗信号&#xff08;self-windowing signal&#xff09;&#xff0c;缓解其频谱分析结果中的能量泄漏现象&#xff08;注意是“缓解”&#xff0c;而不是“避免”或“消除”&#xff09;。所谓信号整周期采样&#xff08…

一个非常流行的R语言调色板:RColorBrewer

R 语言有许多非常优秀的调色板&#xff0c;本文就介绍一个非常流行的&#xff0c;我也经常在用的调色板 R 包&#xff1a;RColorBrewer。 安装 install.packages("RColorBrewer") 加载 library(RColorBrewer) library(knitr) 初探 ?RColorBrewer 在帮助页面可以看到…

在MD编辑器里插入20次方问题

前言 看了很多文章里面没写怎么插入20次方&#xff0c;最后在官网的一篇文章上看到了很详细的数学公式的插入。 问题 大家肯定以为这样就可以了 效果 明显是不行的 解决 使用{}把数字括起来就可以了。 1 20 1^{20} 120 小知识 在行内显示(就是与文字在一起) $ $另起…

详解矩阵的三角分解A=LU

目录 一. 求解Axb 二. 上三角矩阵分解 三. 下三角矩阵分解 四. 矩阵的三角分解 举例1&#xff1a;矩阵三角分解 举例2&#xff1a;三角分解的限制 举例3&#xff1a;主元和乘法因子均为1 举例4&#xff1a;U为单位阵 小结 一. 求解Axb 我们知道高斯消元法可以对应矩阵…

二层交换机和三层交换机

二层交换机&#xff1a;将源mac和端口进行转发&#xff0c;是同一个网段进行通信的&#xff0c;不能实现路由转发&#xff0c;若想跨网段则需要接入一个路由器 如&#xff1a;pc1 192.168.1.1 与 pc2 192.168.1.2通信需要经过二层交换机&#xff0c;二层交换机不能配置ip的&am…

ERP进出库+办公用品管理系统

系统架构 简介系统架构部分页面结构图UML逻辑图办公用品入出库 简介 本系统适用于ERP企业公司职员关于系统化的申请相关办公用品&#xff0c;提高整体系统整合行&#xff0c;加大上下级之间的联系&#xff0c;规避因人员过多&#xff0c;而浪费人力在简单重复的工作中&#xf…

【车载HMI开发工具--EB GUIDE 与 Unity 合作提供一体化的沉浸式 HMI 设计开发工具链】【转载】

随着车载高性能计算平台的日益普及以及显示器尺寸和数量的不断增加&#xff0c;沉浸式车载人机交互界面&#xff08;HMI&#xff09;的需求也在持续增长。为了将实时 3D 技术带入车载 HMI 领域&#xff0c;Unity 与 Elektrobit (EB)展开了合作&#xff0c;EB 是推进 HMI 功能安…

进程间协同:从进程启动、同步与互斥到进程间通信

进程间协同的目的 在操作系统中&#xff0c;进程是计算机进行任务分配和调度的基本单位。在计算机系统中&#xff0c;有很多任务是无法由单个进程独立完成的&#xff0c;需要多个进程共同参与并协作完成。这就像在现实生活中&#xff0c;有些工作需要一个团队来完成&#xff0…

智慧照明迎来新升级:5G/4G智慧灯杆网关助力节能控制

近年来&#xff0c;随着智能科技的飞速发展&#xff0c;智慧照明系统已成为城市建设的热门话题。其中&#xff0c;5G/4G智慧灯杆网关作为智慧照明的重要组成部分&#xff0c;正逐渐引起人们的关注。其能够实现智能控制与远程管理&#xff0c;为城市节能减排做出了巨大贡献。  …

MCU常用外设总线

目录 前言一、时钟与中断二、GPIO三、ADC四、定时器4.1 基本定时器4.2 通用定时器4.2.1 输入捕获4.2.2 输出比较 五、UART六、IIC七、SPI 前言 本文主要讲单片机外设的功能&#xff0c;即这些外设是什么&#xff0c;可以用来干什么&#xff0c;了解了之后我们就可以通过相应的寄…

裁员1600人赔偿8000万,游戏巨头的寒冬要来啦!

据相关可靠消息&#xff0c;网易裁员1600人&#xff0c;消息确认可靠&#xff0c;并且基本都是网易游戏的技术人。 网易是一家靠门户网站起家的互联网公司&#xff0c;并提前布局了网易邮箱。当然最后靠网易游戏提前转型&#xff0c;将竞争对手搜狐和新浪远远的甩着后面啦。 网…

MacM1Pro Parallels19.1.0 CentOS7.9 Install PostgrepSQL

相关阅读 MacM1Pro安装 Parallels Desktop 19.1.0 https://blog.csdn.net/qq_41594280/article/details/135420241 MacM1Pro Parallels安装Parallels Tools https://blog.csdn.net/qq_41594280/article/details/135398780 MacM1Pro Parallels安装CentOS7.9 https://blog.csdn.n…

第十二站(20天):C++泛型编程

模板 C提供了模板(template)编程的概念。所谓模板&#xff0c;实际上是建立一个通用函数或类&#xff0c; 其 类内部的类型和函数的形参类型不具体指定 &#xff0c;用一个虚拟的类型来代表。这种通用的方式称 为模板。 模板是泛型编程的基础, 泛型编程即以一种独立于任何特定…

微软Microsoft推出针对学生的AI练习英语口语工具”阅读教练“:Reading Coach

阅读教练官网链接&#xff1a;https://coach.microsoft.com AI工具专区&#xff1a;AI工具-喜好儿aigc 学生可以通过选择角色和设定&#xff0c;利用AI生成独特的故事&#xff0c;从而激发阅读兴趣并提高阅读流畅度。语音转文本AI能够实时分析学生的阅读流利性&#xff0c;检测…

从 fatal 错误到 sync.Map:Go中 Map 的并发策略

为什么 Go 语言在多个 goroutine 同时访问和修改同一个 map 时&#xff0c;会报出 fatal 错误而不是 panic&#xff1f;我们该如何应对 map 的数据竞争问题呢&#xff1f; 这篇文章将带你一步步了解背后的原理&#xff0c;并引出解决 map 并发问题的方案。 Map 数据竞争 首先…