初始Python篇(11)—— 面向对象三大特征

初始Python篇(11)—— 面向对象三大特征

找往期文章包括但不限于本期文章中不懂的知识点:

个人主页:我要学编程(ಥ_ಥ)-ZEEKLOG博客

所属专栏: Python

目录

封装

继承的基本概念以及使用 

继承

继承的基本概念以及使用 

方法重写 

多态

多态的概念以及基本使用 


 

封装

继承的基本概念以及使用 

封装的概念:隐藏内部实现的细节,只对外提供操作方法(接口)。这个概念我们在上一小节中也已经学习过了,我们主要是去了解其在代码中是如何去实现的:通过有着类似 访问修饰限定符 功能的下划线来实现。

权限控制:通过对属性或方法添加单下划线、双下划线以及首尾双下划线来实现。

下划线种类功能
单下划线开头表示protected,受保护的成员,这类成员被视为仅供内部家族使用,允许类本身和子类进行访问,但实际上它可以被外部代码访问
双下划线开头表示private,私有的成员,这类成员只允许定义该属性或方法的类本身进行访问
首尾双下划线一般表示特殊的方法

代码演示:

class Dog(): # 首尾双线划线 ——> 特殊方法 def __init__(self, name, age): # 双下划线开头 ——> private修饰,只能在类内访问 self.__name = name # 单下划线开头 ——> protected修饰,在类内与子类才能访问 self._age = age # 单下划线开头 ——> protected修饰,在类内与子类才能访问 def _fun1(self): print('这是被protected所修饰的方法') # 双下划线开头 ——> private修饰,在类内才能访问 def __fun2(self): print('这是被private所修饰的方法') # 这里是类外了 dog = Dog('大白', 5) print(dog._age) # print(dog.__name) dog._fun1() # dog.__fun2() # 和上面一样,直接去访问的话,就会报错, # 但是我们可以使用 对象.__dir()__ 或者 dir(对象) 先去查看所有的属性与方法 # 然后通过其中的"属性"与"方法名"去调用真正的属性与方法 # print(dog.__dir__()) # print(dir(dog)) print(dog._Dog__name) dog._Dog__fun2()

 运行结果:

根据上面的访问方式,我们可以推测出:被 protected、private 所修饰 方法 与 属性只是在类中对应的名称发生了变化,而我们不知道,但是可以通过特殊手段知晓,从而继续访问。

但是上面的方式不是很推荐,类似与 Java中的反射机制了,有点反常规。除了上面这种方式,Python还提供了两种方式来实现访问 与 修改 私有是属性与方法。

1、在 私有的方法 或者 属性上,进行套壳处理。

2、在1的基础上,通过 @property 装饰器 来修饰方法,使其变为属性,就变为访问与修改属性了,最终也会变的很简单。

代码演示:

class Dog(): def __init__(self, name, age): self.__name = name self.age = age # 如果想要去访问除了,使用dir()之外,还有两种方式: # 使用实例方法去间接访问与修改 def get_name(self): return self.__name def set_name(self, name): self.__name = name # 使用@property装饰器,将方法转为属性使用 @property def name(self): return self.__name @name.setter def name(self, name): self.__name = name dog = Dog('大白', 5) # 1、通过实例方法的形式去使用 print(dog.get_name()) dog.set_name('小白') print('='*15) # 2、通过@property装饰器,将方法转为属性 print(dog.name) dog.name = '大白' # 修改属性的样式,去传参 print(dog._Dog__name) print('='*15) dog._Dog__name = '小白' print(dog._Dog__name)

运行结果:

注意:我们在使用 @property 装饰器,将属性转为方法时,取值的方法,必须被 @property 修饰,而修改值的方法,必须被 @取值方法名. setter修饰。

我们的建议是:是对哪个变量进行取值 与 修改值,就将方法名设置为哪个变量,这样修改方法的装饰器也很容易写,负责容易混淆,而且可读性不高,不易于别人读。这里也体现了封装的特性,隐藏内部实现细节,只对外提供接口。 

继承

继承的基本概念以及使用 

继承是指一个类(子类、派生类)继承另一个类(父类、基类)的属性与方法。

在Python中一个子类可以继承N多个父类,这是与 Java决然不同的一点。Java属于单继承,而Python属于多继承,并且每个类都默认继承自object类。当然,一个子类可以有多个父类,一个父类也可以有多个子类。

语法:

class 类名([父类列表]):

注意:当一个类的父类只有object类时,默认是可以不写父类的,但是如果一个类有除object类之外的其他类,就需要将这些类全部写到 () 中,当然这个()在只有继承object类的情况下,也是可以不写的,但是建议还是要写上去。

代码演示:

# 默认继承object类,但是这个可以不写 class Animal(object): def __init__(self, name, age, gender,sort): self.name = name self.age = age self.gender = gender self.__sort = sort class Dog(Animal): pass # 子类继承父类,会将父类中除private修饰的方法与属性全部拿过来 # 继承了 __init__方法,以及 name、age、gender属性 dog = Dog('大白', 5, '男', '中华田园犬') print(dog.name) print(dog.age) print(dog.gender) # 同样需要特殊手段才能访问到 print(dog._Animal__sort)

运行结果: 

注意:我们在实例化一个对象时,会先去调用构造方法(init 方法)给对象的属性进行初始化赋值,如果一个类没有构造方法,但是由于这个类是默认继承自object类,因此会调用object类中默认的 init 方法,但如果这个类继承了其他类,就会先在其他类中去搜索这个方法,如果有则调用;反之,则还是去调用object类的。 而在上面的代码中,Animal 类是有 init 方法,因此会去调用Animal 类的。

我们再看看多继承的代码:

class Person(): def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def show(self): print(f'我叫{self.name},今年{self.age},性别是{self.gender}') class Father(Person): def __init__(self,name,age,gender): # 可以直接调用父类的初始化方法 super().__init__(name,age,gender) # 下面这种方式是错误的 # super().name = name # super().age = age # super().gender = gender # 下面的方式也行,但是不推荐 # self.name = name # self.age = age # self.gender = gender class Mother(Person): def __init__(self, name, age, gender): # 可以直接调用父类的初始化方法 super().__init__(name, age, gender) # 下面这种方式是错误的 # super().name = name # super().age = age # super().gender = gender # 下面的方式也行,但是不推荐 # self.name = name # self.age = age # self.gender = gender class Son(Father, Mother): def __init__(self, name, age, gender): # 可以直接调用父类的初始化方法 super().__init__(name, age, gender) # 下面这种方式是错误的 # super().name = name # super().age = age # super().gender = gender # 下面的方式也行,但是不推荐 # self.name = name # self.age = age # self.gender = gender father = Father('A',40,'男') mother = Mother('B',35,'女') son = Son('C',10,'男') father.show() mother.show() son.show()

运行结果:

上面的代码中,Son类、Mother类、Father类都是继承自Person类的属性与方法,它们是公用Person类的属性与方法。

注意:上述 Son类继承了多个父类,当我们去使用 super().init 方法初始化子类对象时,默认是按照父类在Son()中的顺序来查找的,这里是Father类定义声明在前,因此这里调用的就是 Father 类的 init 方法,如果想要指定某个类的 init 方法的话,就需要使用 类名.init() 方法。例如:

# 这里的self代指当前Son类的实例对象 Mother.__init__(self,name,age,gender) # 可替换Son类中是super.init

方法重写 

当子类继承父类时,子类就拥有了父类中的 公有成员、方法和受保护的成员、方法。如果我们对父类中有些成员不满意的话,子类就可以重新定义成员。同理,方法也是如此,但是重新定义方法麻烦了,那有什么办法呢?方法重写,即 偷梁换柱,表面上这个方法还是原来的方法,但是其内部实现的结构早就发生变化了。

重写的要求:方法名必须一样,至于方法的返回值类型,参数列表、访问权限这些可以不一样。

代码演示:

class Animal(): def __init__(self,name,age): self.name = name self.age = age def eat(self): print(f'{self.name}正在吃食物,补充体力') class Dog(Animal): def __init__(self,name,age): super().__init__(name,age) # 由于Animal类的eat方法只是随便说在吃啥,并不具体, # 但我们想要打印出具体的食物,因此可以重写(外壳不变,核心变化) def eat(self): print(f'{self.name}正在吃狗粮~') class Cat(Animal): def __init__(self,name,age): super().__init__(name,age) dog = Dog('大白', 5) # 子类重写父类的方法之后,父类再去调用eat方法,就不再是调用父类的,而是自己的 dog.eat() cat = Cat('小白', 3) # 子类没有重写父类的eat方法,因此还是去调用父类的eat方法 cat.eat()

运行结果: 

其实,重写就是在子类中定义了一个与父类重名的方法,只不过因为 Python中语法的检查不是很严格,因此这里就很容易不理解。 

在Python中,我们就将重写看作是子类定义了一个与父类重名的方法即可,在调用时,如果子类没有这个方法,那么就是调用父类的同名方法,如果还没有就会报错。但如果子类有这个方法,那么就是直接调用子类的方法,即使父类有,也不去调用("地头蛇原则")。

多态

多态的概念以及基本使用 

多态是指多种形态,当去完成某个行为时,不同的对象可能会产生不同的形态。

例如,我们在类和对象中说的小故事:当刘建明 与 陈永仁 遇到 韩琛 时,两人打招呼的方式不一样,这就是不同对象 在 完成同一个行为时,两者所产生的形态不同。

再比如,我们每天都会吃早餐,但是不同的人 在 面对这件事情时,所表现出的行为就不一样,A 可能吃面条,B可能吃包子、饺子,C可能吃大米饭等。

Python中的多态与Java、C++不同,Python中的多态只需要满足有该方法,然后让不同的对象去调用即可,而 Java 中的多态需要满足三个条件:向上转型(父类引用指向子类对象)、子类重写父类的方法、向上转型的父类调用该方法(被重写的方法),这时就不再是调用父类的方法,而是调用子类的方法。但 Python中,只要这两个类有相同的方法,当两者赋值给同一个对象时,去调用同一个方法就会表现出不同的行为。

其实,多态就是表层对象一样,内部实际的对象不一样,那么在调用同一个方法时,虽然看似是这个表层的对象所调用的,但实际是内部的对象所调用并执行的。

代码演示:

class Animal(): def eat(self): print('正在吃东西') class Person(): def eat(self): print('正在干饭') class Dog(): def eat(self): print('正在吃狗粮') class Cat(): def eat(self): print('正在吃猫粮') # 定义一个函数,传入obj对象,并调用该对象的eat方法 def eat(obj): obj.eat() # 方法得通过类或者对象去"."调用,而函数是直接传参调用,不要弄混了 eat(Animal()) # 这里需要传入对象,即:类名() eat(Person()) eat(Dog()) eat(Cat())

运行结果:

好啦!本期 初始Python篇(11)—— 面向对象三大特征 的学习之旅 就到此结束啦!我们下一期再一起学习吧!

Read more

基于Milvus与混合检索的云厂商文档智能问答系统:Java SpringBoot全栈实现

基于Milvus与混合检索的云厂商文档智能问答系统:Java SpringBoot全栈实现

基于Milvus与混合检索的云厂商文档智能问答系统:Java SpringBoot全栈实现 面对阿里云、腾讯云等厂商海量的产品文档、规格参数与价格清单,如何构建一个精准、高效的智能问答系统?本文将为你揭秘从技术选型到生产部署的完整方案。 云服务商的产品生态系统日益庞大,相关的技术文档、规格参数、定价清单等文档数量急剧增长。传统的文档查找方式已无法满足开发者和运维人员快速获取准确信息的需求。 基于检索增强生成(RAG)的智能问答系统成为解决这一难题的有效方案。本文将详细介绍如何使用 Java SpringBoot 和 Milvus 向量数据库,构建一个面向云厂商文档的高效混合检索问答系统。 一、核心挑战与架构选型 云厂商文档具有鲜明的技术特点,这些特点直接影响了我们的技术选择: 1. 高度结构化:包含大量技术规格表、价格矩阵和配置参数 2. 专业术语密集:如“ECS.g6.2xlarge”、“对象存储每秒请求数”等精确术语 3. 多格式混合:Markdown、PDF、Word、TXT等格式并存 4. 版本频繁更新:产品迭代快,文档需要及时同步

By Ne0inhk
一文通关 MySQL 数据类型,打好高性能数据库的第一战!

一文通关 MySQL 数据类型,打好高性能数据库的第一战!

🔥海棠蚀omo:个人主页                 ❄️个人专栏:《初识数据结构》,《C++:从入门到实践》,《Linux:从零基础到实践》,《Linux网络:从不懂到不会》,《MySQL:新手入门指南》                 ✨追光的人,终会光芒万丈 博主简介: 目录 一.数值类型 1.1tinyint类型 1.2bit类型 二.小数类型 2.1float类型 2.2decimal类型 三.字符串类型 3.1char类型 3.2varchar类型 3.3char和varchar的比较 四.日期和时间类型 五.enum和set 5.1查询set中的数据 前言: 在上一篇文章中,我们学习了库和表的相关操作,而在我们上一篇的讲解中,我们提到了在列名后面跟的是数据类型,但是对于MySQL中的数据类型我们现在还一知半解,那么今天这篇文章我们就来详细谈一谈MySQL中的数据类型。 那么在详细讲解每种数据类型之前,

By Ne0inhk
一键部署,告别下载烦恼:这款高颜值PHP内网软件库,让办公协作飞起来!-小散软件库

一键部署,告别下载烦恼:这款高颜值PHP内网软件库,让办公协作飞起来!-小散软件库

嗨,亲爱的伙伴们,我是走小散 在工作时,你是否遇到过这类情况: A同事用着不错的软件,但下载流程异常繁琐; B同事的办公软件版本过低,无法打开A同事的高版本文件。 别担心,只需请网络管理员为你们公司量身搭建一套专属的内部软件库,问题就能轻松解决! ‘ 环境说明 php8.3 mysql5.7 需要安装的PHP扩展 mbstring 权限 请给uploads文件夹配置755权限 上传大小 默认配置100G最大上传大小 php.ini(或面板里的 PHP 配置)建议至少设为: upload_max_filesize = 100G post_max_size = 100G(建议 ≥ 上传大小) 大文件上传时间长,可适当调大: max_execution_time = 36000(或更大,单位秒) max_input_time

By Ne0inhk
Flutter 组件 highlighter 适配鸿蒙 HarmonyOS 实战:高性能语法高亮,构建大规模代码分析与文本染色架构

Flutter 组件 highlighter 适配鸿蒙 HarmonyOS 实战:高性能语法高亮,构建大规模代码分析与文本染色架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 highlighter 适配鸿蒙 HarmonyOS 实战:高性能语法高亮,构建大规模代码分析与文本染色架构 前言 在鸿蒙(OpenHarmony)生态迈向专业化工具链、涉及海量日志审计、在线编程教育及开发者社区分发的背景下,如何为长篇累牍的源代码实现毫秒级的语法高亮与结构化展示,已成为决定用户阅读体验与知识传递效率的“视觉分水岭”。在鸿蒙设备这类强调 AOT 极致性能与复杂文本排版(Text Layout)的环境下,如果应用依然依赖基础的正则表达式进行低效的字符匹配,由于由于解析算法的复杂性,极易由于由于“主线程阻塞”导致大型文件在滑动过程中产生严重的掉帧与视觉黏连。 我们需要一种能够支持多语言语法解析、具备词法分析(Lexing)深度且兼容 RichText 富文本输出的高性能染色方案。 highlighter 为 Flutter 开发者引入了基于标准词法字典的语法高亮引擎。它不仅能精准识别不同编程语言的关键字、操作符与注释,更利

By Ne0inhk