开篇
面向过程编程和面向对象编程是两种基本的编程思想。
很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:1097524789
在这之前,你学习到的都是面向过程编程,即:首先分析出解决问题的每个步骤 ,然后编写函数实现每个步骤,最后通过合适的顺序依次调用函数来解决问题。
不同于面向过程编程,面向对象编程的思想其实是从自然界的机理中借鉴而来的。正所谓物以类聚,在渺渺的大自然中,有数不胜数的类别,按照不同的星球来分类,可以分为:地球类、太阳类、火星类、月球类、海王星类等等
按照地球上的不同形态的生命,可以分为植物类、动物类、细菌类等等
对比面向过程,初识面向对象
在介绍各种概念之前,让我们先做一个小栗子,通过对比面向过程编程的方式去感受面向对象编程的奥妙。
栗子如下:
小明家里养了3只小猫,每到中午饭点,这三只小猫便要吃饭了。吃饭前,小猫们都会 先洗手,然后喵喵叫三声。请写一个程序,来分别模拟这三只小猫完整的吃饭过程,部分细节可自行脑部。
分析问题,可以绘制出解决问题的流程图
如果采用面向过程思想进行编程,可以这样写:
首先分别用函数实现以上流程图中的三个步骤
有了函数之后,就可以按照合适的序列步骤调用函数来解决问题了:
得到如下输出:
而若采用面向对象编程,则可以写出如下代码(稍后会对每一句代码进行解释,这里只是先直观感受下面向对象编程的feel):
得到同样的输出:
在上面的代码中,我们使用关键字class
定义了一个小猫吃饭的类,名字叫做CatMeal
,然后实例化出来了3
只小猫,分别模拟了它们吃饭的完整过程。你可能还是对有些代码,比如__init__
那里搞不清,没关系,先别着急,在下一部分,我们将详解上述代码,在此之前,有一些东西需要讲一下:
如果你阅读过之前的文章,你会发现,那些文章的思路都是先通过介绍某种方法的不足,然后引出正题,比如由于需要用多个变量来存储多个数字,于是引出了列表这一简单高效的数据结构。在这里,我们先介绍了面向过程的方法,之后才介绍了面向对象的方法,那是不是面向对象比面向过程更具有优势呢?
并不是,这两种编程思想各有千秋。
我们可以按照从简到繁的顺序来捋清这一切:
(1)对于一个非常简单的问题,比如计算两数之和,我们甚至可以直接在命令行中敲下a+b
,点击回车即可看到问题的答案:
(2)接着将问题变复杂些,这次也是计算两数之和,只不过待计算的数值对不止一个,于是我们可以定义一个函数,专门用于做两数之和:
(3)然后,将问题更加复杂化,需要一个简易版计算器,可以用来计算加法和减法,并且要求用户只需输入操作数(待运算的数字,比如1,2,3),而无需输入运算符(比如+,-):
采用面向过程的思想,我们需要定义加法和减法两个函数
而若采用面向对象的思想,我们可以这样写:
在上面的代码中,我们定义了一个计算类,名字叫做Cal
接下来从这个类中实例化出来一个对象,名字叫做z
输出结果
(4)如果现在去除了用户不能输入运算符的限制,那么,使用面向过程编程的代码如下:
使用面向对象编程代码如下:
再次对比这两者,可以看出,面向对象编程给人的感觉是代码变得麻烦了些,而面向过程编程则清爽很多。
原因在于,实现加法和减法是个很简单的问题,在这个问题上使用面向对象的编程方式不能很好的体现出面向对象编程的灵活性和规范性,反而简单的面向过程编程更加易懂、易实现。
在今后,你会看到,当问题规模变大时,面向对象编程将会体现出来显著的优势。
总结来说:面向过程和面向对象这两种编程方式各有千秋,在解决规模较小的问题时使用前者更为方便,而对于大规模问题,后者具有显著优势。当然这也不是绝对的。在性能和维护成本等方面,两者也是不同的。所以,对于不同的应用场景,要学会灵活选用不同的编程方式。
面向对象编程的语法
在这一部分,我们将对之前栗子中面向对象代码进行拆分讲解。
定义一个类
在class CatMeal():
中:
class
是一个Python
关键字,表明要定义一个类,它的作用就好比定义函数时用到的关键字def
CatMeal
是类的名字,一般约定首字母大写的代表类名,而首字母为小写的代表变量命
在还没有学习后面的内容之前,当你想创建一个新的类时,只需修改类名即可,其余照抄,比如定义一个动物类,可以写class Animal():
。当然,在后面的学习中,你会解锁关于这一句代码的更高级用法。
在类中定义方法
我们知道,以关键字def
定义的一个代码块叫做函数,用于完成特定的功能。其实,在类里面,也是使用def
定义一个代码块,同样是用于完成特定的功能,只不过此时的名字不再是“函数”,而是“方法”(本质上还是函数)。在这个栗子中,定义的__init__
、eat
、wash
、miao
都是方法。
__init__
方法默认第一个参数是self
(约定俗成的叫法),后面的参数可以自行指定,就像给函数传参那样。
在__init__
方法里,以参数形式定义特征,称之为属性。
比如本栗中的number
和food
就是类中定义的两个属性,你可以类比着添加更多属性。
当然,如果像之前的简易计算器栗子一样,不要求在创建类时手动指定属性,那么就可以不显式地写出__init__
方法(可以回看那个栗子来加深理解)。
观察eat
、wash
、miao
方法,你会发现,每个方法里面都和__init__
方法一样,第一个参数为self
。
其实,无论是__init__
方法也好,其余自定义的方法也罢,它们的第一个参数都必须是self
,它代表一个完整的实例化对象。与类相关联的属性和方法都会自动传递给self
,通过使用self
,可以轻松调用类中的一些属性和方法:
比如在eat
方法中,我们传入了self
,于是便可以在该方法中使用self.number
获取在__init__
方法中定义好的number
具体值,同理可以使用self.food
获取food
的具体值。
从类中实例化对象
在编写完成这个CatMeal
类之后,便可以通过类来实例化对象了,比如:
miao1=CatMeal(1,'树叶子')
运行这一句代码,会从抽象的类中实例化出来一个对象,名字叫做miao1
,同时自动调用__init__
方法,并将1
和树叶子
分别传给__init__
方法中的number
和food
。
其内部具体实现过程如下:先在内存中开辟一块空间,然后调用__init__
方法,并让self指向那块内存空间,最后让实例化的对象miao1
也指向那块内存空间。
这个实例化的对象miao1
可以通过.
来访问类中的属性和调用类中的方法,比如访问food
属性,可以写miao1.food
;调用wash
方法,可以写miao1.wash()
。
总结
初学者很容易被一堆self
所困扰,所以这里尽量使用精炼的语言来总结第二部分所讲内容:
在定义类之后,实例化之前,self
这个抽象的东西具有访问类中属性和调用类中方法的权限,所以无论是增加属性,还是增加方法,都离不开self
。增加属性可以写self.new_attribute=new_attribute
,增加方法可以写
(可以根据需要自行设定方法中的参数)
比如在定义eat
、wash
、miao
方法时,由于还没有实例化对象,因此若要访问类中的属性number
和food
,必须借助具有权限的self
。因此,每个方法都需要传入self
这个参数,以使用self.
来进行访问。self
仿佛就是一把钥匙。
而在实例化(比如miao1=CatMeal(1,'树叶子')
)之后,原先self
具有的权限将会复制一份给这个实例化的对象。
之前需要使用self.number
来访问number
属性,现在依然可以,但同时也支持使用实例化对象.number
来进行访问了,比如miao1.number
。
以上就是本期全部内容了,大家好好消化一下吧