笨方法学Python:面向对象

今天开始跟大家讲面向对象,对于编程而言,面向对象是一个很重要的知识点,但说到底它其实就是一种编程思想。正常来说,编程有两种思想,一种叫做面向过程,另一种叫做面向对象。

面向过程就是我们之前写的那些代码,大概意思有点像现实生活中的流水线生产,考虑周全之后,只需要顺着要执行的步骤,堆叠代码即可;而面向对象就不同了,它有点类似于模块化生产,用代码写完各个模块之后,根据你的需求调用这些模块。

前者主要应用在一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等,后者应用于需求经常变化的软件,比如网站,APP,游戏等。所以学习面向对象的编程思想可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。先给大家看下面向对象知识的思维导图。

在之前有跟大家说过在Python里面,一切皆对象,所以其实一个函数,一个变量是一个对象,而函数、变量这些大集合就叫类。其实面向对象很适合用于描述现实世界,比如人是类,而你,我许许多多的个体就是对象,类和对象其实就是这种关系。而对于正常人来说,会有年龄,名字的属性,会有吃饭睡觉学习的技能,这两者对应的就是类的变量和函数,只不过我们在面向对象中经常把这两者称为属性和方法,但其实是一样的,不要太纠结叫法:

在Python中,类的构造就像上图,类的命名正常是首字母大写,如果遇到两个单词的话,建议是单词首字母大写,例如SendMail,SaveMail;名字后面的括号可以空着,里面是用于填写父类名用于继承的,这个后面会将,可以空着没关系;

类的内部正常是变量和函数,也就是属性和方法。(后面我会用这个称呼了,大家也适应过来)类的使用需要实例化,其实不用太纠结实例化是什么意思,知道如何做就可以了,Python的实例化很简单,就是这样(有点像赋值给一个变量):

结果如下:

1. 属性

属性分为类变量和实例变量,类变量就是这个类的变量,也就是上面例子中的name,age;实例变量则是在方法里面的变量,需要实例化类之后才可以用,比如上面例子的food,bed,what,大家会发现它们的前面有加self,加了它意味着是这个方法的变量,不加的话Python会认为变量是外面的实例变量,所以必须加上self。

类变量则是这样使用的:

区别就是实例变量必须实例化才能调用,类变量不用。

2. 方法

与变量一样,方法分为实例方法与类方法,意思也和上面的变量差不多,只不过类方法长这样:

运行结果:

方法的调用是加个括号。大家会发现类方法比实例方法多了一个@classmethod,这个叫装饰器,是用于Python识别的,类方法是cls而不是self,因为cls是class(类)的缩写,类方法用cls.是可以直接调用类变量的,但是实例方法不可以直接调用类变量。

实例方法调用是这样的:

括号里填东西是因为上面例子的方法需要传入参数,如果你的方法不需要传入参数,仍需要保留self,比如:

接下来讲一下静态方法,和类方法一样,静态方法也是用装饰器区分的,长这样:

可以看出,相对于类方法,静态方法并不需要cls,其实它就是一个普通函数。

3. 构造函数

其实Python中的构造函数就是名为__init__的函数,它正常是用于初始化的,这个函数有个特点就是它不需要调用就会执行,有点像之前的__init__.py文件,所以比如你的网页想判断用户是否登陆就可以使用它,就不需要每次都调用一个方法来判断了。

需要注意的是,构造函数是不能返回值的,假如你在里面加上return,它就会报错:

4. 成员可见性

这里说的成员就是指属性和方法,所谓的成员可见性是指属性和方法是否可以公开被外部引用,像我们上面的例子就都是可以公开被外部引用,但假如你出于安全考虑,不想让其他人随便引用某些属性或者方法,就可以将属性或者方法私有化。Python私有化的标志是名称前面加__,比如__learn()。

举个例子好理解一点吧,以上面例子,一个人只有睡眠充足才有精力学习,如果没有睡够觉,是无法拥有学习这个技能的,Python就可以使用私有方法实现:

运行结果:

假如你直接从外部调用私有方法,就会报错:

这里有个比较有趣的现象是假如你定义了一个私有属性,你会发现你居然可以从外部给这个属性赋值并打印:

但其实这只是看起来像而已,实际上你并没有给私有属性赋值,而是你创造了一个新的实例属性,记住,是实例属性,私有属性还是那个私有属性,没有变,可以试着不赋值打印私有属性,你就会发现报错了:

这里提供一个Python内置的方法给大家查看变量,叫__dict__,以上面例子为例,你会发现打印出了两个属性:

5. 面向对象三大特性

对于三大特性,主要跟大家讲一下继承性和多态。封装就是把类中的属性和方法定义为私有的,上面已经讲了,就不继续讲。

那就来说下继承,继承前提是要先抽象,抽象其实可以理解为抽出两者或多者像的特征,比如:

继承的话其实可以这样理解,你爸酒量很好,但是不会抽烟,生下了你,继承了他的酒量,又学会了抽烟,变得会抽烟会喝酒,这就是继承。用代码表示就是这样的:

运行结果:

需要注意的是有时候可能你的父类和子类有同名的方法,Python会使用子类的方法,举例如下:

Python相对于其他语言比较特殊的是它支持多继承,也就是说它不只是可以继承一个父类的方法,而是可以继承多个父类,举例如下:

继承最后一个要讲的是子类继承父类构造函数的问题,假如父类已经有了构造函数,子类也有构造函数,构造函数有同样的实例属性,就要这样写才能调用:

但试想以下,假如你父类突然换名字了,那你子类也需要跟着换,这会很麻烦,所以这样写的话就可以解决这个问题:

即super(子类名,self).__init__(参数)。

下面讲讲多态。要理解什么是多态,我们首先要对数据类型再作一点说明。当我们定义一个类的时候,我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样,而判断一个变量是否是某个类型可以用isinstance()判断:

看来a、b、c确实对应着list、Father、Son这3种类型。但是试下这个:

你会发现c不仅是Son,还是Father。原因是Son是从Father继承下来的,也就是说多态其实就是父类下的一种表现形态,但它依旧有着父类的类型。但是,反过来是不行的:

理解多态的好处,我们可以定义一个函数,并传入父类和子类,打印出如下结果:

你会发现,新增一个Father的子类,不必对chouyan_twice()做任何修改,实际上,任何依赖Father作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。

多态的好处就是,当我们需要传入Son时,我们只需要接收Father类型就可以了,因为Son都是Father类型,然后,按照Father类型进行操作即可。由于Father类型有chouyan()方法,因此,传入的任意类型,只要是Father类或者子类,就会自动调用实际类型的chouyan()方法,这就是多态的意思。

好了,以上便是面向对象的所有内容,有点多,希望大家能反复消化理解一下,有不懂的地方可以在文章底下留言问小编,小编会尽自己努力解决大家的疑问。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181222G14XZG00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券