IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 【面向对象】3句话,让群青写了18小时的面向对象教程! -> 正文阅读

[Python知识库]【面向对象】3句话,让群青写了18小时的面向对象教程!

1. 什么是面向对象程序设计?

面向对象程序设计是一种编程架构。面向对象的一条基本原则是计算机程序由单个的能够起到子程序作用的单元或对象组合而成,这些对象也被称为模型。

面向对象程序设计作为一种新思想,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。模型不可能做到到完全反映出一类事物的一切具体特征,而是只能对其特征和变化规律进行抽象、拟合,从而使其更具有客观性、普遍性。

就好比,如果我们有一只鸟,我们不可能从生物学角度上将其所有生物特征与生物行为提取出来;但是我们可以将其具有代表性的特征抽出,让这些特征作为能表示其一般规律的基本特征。比如,鸟有翅膀、喙、爪子,而且会飞等等。

所以在传统的面向过程的编码过程中,我们想实现某一类复杂亦或高级功能(比如实现复数的计算)时就会显得捉襟见肘:在代码规模较小时,其实面向过程编码与面向对象编码的效率是很相近的,甚至相比之下,采取面向对象思想的代码整体架构会显得相对冗余一些。这些冗余可能在前期并不能发挥他真正的作用,所以,不妨等到了它真正的用武之地时再作定论。

2. 面向对象思想的三大基本特征

与传统面向过程的编码方式相比,面向对象思想具有这三大特征:封装、继承和多态。下面将通过具体的代码示例(以Python语言为基础)为大家做更深入、形象的讲解,同时也会融入我自己个人的理解:

2.1 封装

封装是指将一个计算机系统中的数据以及与这个数据相关的一切操作语言(即描述每一个对象的属性以及其行为的程序代码)组装到一起,一并封装进一个有机的实体中,把它们封装在一个“模块”中(其实就是类里)。

以上引用是百度百科给出的权威解释。当然,也有一部分解释是这样的:

对一个普通类进行封装,就是为其变量添加修饰符来限制访问,在本类的内部可以被随意访问,但对外只能通过本类对外提供的接口实现访问操作(如getter和setter方法)。

其实几种说法各有各的道理,下面是我自己的见解:

封装是一个过程,它无非就是从所有客观阐释的规律中抽象部分特征并提取,然后将其组合,成为一个新的整体,这个过程叫抽象。但对于我们抽象得来的属性也好方法也罢(下文如果不具体指明的话统称为”成员“),单单地把它们放在那里难免会出现一些问题,比如说某个类里的成员变量被随意篡改、某个成员方法的业务逻辑出现严重问题等等,所以这个时候需要对他们的访问做出限制,这个做出限制的过程叫封装。

可能有点长,大家会懵,简单来说就是:封装 = 抽象+ 访问限制。其实在以后的学习中也是这样,将复杂的概念抽象为一个简单明了的数学公式也不失为一种高效的理解方式。

然后接下来的内容学过C++、Java的朋友可能会非常熟悉了。既然要对成员做出修饰,那么如何进行修饰呢?在类C语言中,无非就是为其添加访问修饰符,public、protected、private等等。但是,由于本次我们的教程基于Python语言,这里可能会稍稍有些不同,但是也很简单,比较Python的特点就是简洁。

首先还是有必要说明一下这几类修饰符的区别:

ModifiersClassPackageSubclassWorld
publicyyyy
protectedyyyn
Noneyynn
privateynnn

对这三类修饰符的说明如下:

  • public:以该修饰符修饰的成员允许被任何地方调用
  • protected:以该修饰符修饰的成员只允许被当前类及其子类调用
  • private:以该修饰符修饰的成员只允许被当前类调用

这里可能有一个思维误区:认为没有修饰符的变量就是public的,这个在类C语言中是严重的错误,不妨看看下文Python中是如何定义的呢?

在Python中,我们如何对成员进行封装呢?同样还是这三种修饰关系,但是修饰的语法简单变换了一下:

Access ModifiersPrefix of members
publicNone
protected_
private__

通过上表其实很容易看出,Python将其简化成了成员标识符的前缀。如果该成员为公有的,则不加任何前缀(这里的前缀指下划线);若该成员为受保护的,则为其标识符前添加一个下划线即可;私有成员则添加两个下划线作为前缀即可。

  • 注:Python中前后双下划线的成员不表示私有,而是表示特列方法,即用户控制的命名空间内的变量或是属性,只有当文档中有说明是才使用,自己不要定义此类成员!!

正是因为封装性的存在,程序操作的复杂度大大降低,同时也实现了”高内聚、低耦合“的设计理念。

2.2 继承

其实继承性单从名字上来听就很浅显易懂了。首先还是来看看权威解释:

继承主要是指两种或两种以上的类之间的联系与区别。继承不单单是后者对前者某些方面特点的延续,而是指一个对象针对于另一个对象的某些独有的特点、能力进行复制或者延续。

很高深😂😂

其实结合我们日常生活中的一些常识来看也很好理解:子代可能会从父代那里继承很多父代的特征,但是这些特征并不是一成不变的,而是会随着子代的成长不断变化、不断更新迭代,最后将其变成自己所属的特征的过程。

这个论证其实在面向对象思想中得到了非常好的认证:对于父类,子类可以通过继承得到父类的成员,方法也好,变量也好,都可以通过继承得到。但可能会出现这么一种情况:对于某个特定成员方法,子类已经不想单单地只从父类中继承得到了,而是在继承之后通过自身的”再加工“,添加属于该子类自己的逻辑,从而将其变成真正的自己的成员方法。这个过程就是继承。

当然,这个”再加工“的过程也不是必须要有的,这个需要结合实际情况具体分析。

举个栗子:

# !/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@Author  : UltraMarine
@File    : main.py
@Time    : 2021/7/25 17:36
@Software: PyCharm 2021.1 x64
"""

class A:
    def __init__(self):
        print('__init__ method from A')


class B(A):
    def __init__(self):
        super(B, self).__init__()


if __name__ == '__main__':
    B()

通过上面的代码,我们可以创建一个类B继承自A,B的构造方法完全继承于其父类A,所以在实例化B时,调用其构造方法实际上直接且只调用了其父类A的构造方法:

还可以通过改变子类待继承方法参数列表、方法体等方式进行重载:

class B(A):
    def __init__(self):
        super().__init__()
        print('__init__ method from B')

这样在实例化时,运行的结果为:

在Python中,子类执行构造方法有以下三种情况:

  1. 子类不重写__init__方法,实例化子类时,会自动调用父类定义的__init__方法
  2. 如果重写了__init__方法,实例化子类时,就不会调用父类的__init__方法
  3. 如果重写了__init__方法,但是希望继承父类的构造方法,可以使用super(子类名称, self).__init__(父类参数列表)继承

2.3 多态

首先还是看看官方给出的解释:

程序运行时,相同的消息可能会送给多个不同的类别的对象,而系统可依据对象所属类别,引发对应类别的方法,而有不同的行为。简单来说,所谓多态意指相同的消息给予不同的对象会引发不同的动作。

其实也比较好理解,我理解的是这样:在实际项目中,数据需求并不是一成不变的,一套接口可能只能实现大部分需求,然而另一部分需求就会因无法被处理而被搁置。所以为了解决资源不统一的问题,能否通过判断传入参数的不同而分别调用不同的方法,这就是多态。

多态可分为变量多态与函数多态。变量多态是指:基类型的变量(对于C++是引用或指针)可以被赋值基类型对象,也可以被赋值派生类型的对象。函数多态是指,相同的函数调用界面(函数名与实参表),传送给一个对象变量,可以有不同的行为,这视该对象变量所指向的对象类型而定。因此,变量多态是函数多态的基础。

当然,在我看来,多态还是要分为两个角度来看的。

首先,就像上文所提及的那样,支持不同参数不同功能的方法使用同一方法名。这样做增加了程序的灵活性和可扩展性,是传统面向过程编程所体验不到的。

然后便是接下来要提到的继承多态。直接说可能会很抽象,这里举个例子:我一开始定义了一个超类Bird,不妨结合我们的日常生活,这个Brid类其实有很多的派生类,比如我还可以在下面创建其派生类Chickenduck等等,代码示例如下:

# !/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@Author  : UltraMarine
@File    : main.py
@Time    : 2021/7/25 17:36
@Software: PyCharm 2021.1 x64
"""

class Bird:
    def __init__(self):
		pass

        
class Chicken(Bird):
    def __init__(self):
		super(Chicken, self).__init__()

        
class Duck(Bird):
    def __init__(self):
		super(Chicken, self).__init__()

...

这说明一个基类可以有多种子类,其派生-继承关系构成了一个庞大的网络。

  • 注:第二种情况被称为多态,而第一种情况被称为多态性,两者是不同的概念!!

3. 个人小tips

其实在Python包中,为了方便模块的管理,我会把这个包中可能会用到的全局类放在__init__.py中。

或者,我这个包本身就是一堆模块的集合,就可以在__init__.py中将这些模块全部导入,然后直接引用这个包就可以辣~~

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-07-27 16:10:51  更:2021-07-27 16:11:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/8 1:39:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码