前言
前面说完了pyhton的基础,说完了数据类型和函数的一些定义,那么我们能够通过函数把一些有关联的代码发在一起然后调用,那么我们如果有很多个写好的函数是不是也可以用这样的思想去把它封装起来。python或者主流的编程语言就有这样的一种编程思维,叫做面向对象编程。
1.面向对象编程介绍
1.1面向对象基本概念
面向对象编程的英文缩写叫OOP,它的全称是Object Oriented Programming 。有这么一句话是这样说的:“在面向对象的世界里, 万事万物皆对象。”
以往的传统编程称为面向过程,是根据需求,将某些独立功能封装成一个又一个函数,最后完成的代码就是顺序调用不同的函数。
但是面向对象,相比较函数来说面向对象是一个更大的封装,根据职责在一个对象中封装多个方法(也就是函数),也可以说根据职责确定不同的对象,在对象内部封装不同的方法。
1.2面向对象编程介绍
1.2.1 类和对象的概念
从上图也可以看出来我们面向对象主要的概念有类和对象,那么什么是类什么是对象?
类其实就是对具有相同特征或者行为的事物的一个统称 ,它是抽象的不能被直接使用!
举例来说,最常见的就是我们人类,我们的身高和年龄这样的静止的固定特征可以是我们人类的属性,那么我们跑和跳这种动态的行为可以是我们人类的方法。因此,类这个抽象的概念主要包含的就是两个
1.静态 - 属性 2.动态 - 方法
那么对象的概念是什么?
对象就是由雷创建出来的一个具体存在的事物,可以直接使用。
ps:由 哪一个类创建出来的对象,就拥有在哪一个类中 定义的 属性和方法。
1.2.2类的设计
那么我们怎么设计一个类?通常设计类我们一般有以下的三个步骤组成:
1.类名 同类事物的名字,命名满足大驼峰命名法
2.属性 同类事物具备的特征
3.方法 同类事物具备的行为
例如,狗这个抽象的类,我们就可以有类名叫“Dog”,属性:“名字/年龄/体重”,方法:“吃/喝/睡觉”。
1.3面向对象基本语法
其实面向对象的语法主要是一个对类的定义这样的语法框架,如下图所示先记忆稍后再来讲self.
class 类名:
# 方法:定义方式与函数基本相同,区别是方法的第一个参数必须为 self
def 方法1(self,参数列表):
pass
def 方法2(self,参数列表):
pass
当按照上面代码框里的语法框架定义了我们的类之后,我们想要去使用类里的方法该怎么调用呢?这时候就要用到我们的对象了,我们使用上面定义好的类来创建我们的对象。语法格式如下:
对象变量名 = 类名() # 声明对象变量名也被称作 实例化对象
1.4案例1
那么知道了上面如何创建类,创建对象之后我们就可以来简单的实现一个面向对象的编程脚本。
能明显的看出来我们在对Cat这个类声明了一个具体的对象tom,那么我们就可以通过这个tom对象来调用Cat类里的方法,可以理解成tom是Cat这个类里的具体的一份子,那么我们就能够有和它相同的行为了。
1.5self参数
既然上面的案例1我们讲到了调用类里的方法了,那么前面还说了我们一个类里除了方法还有类的属性。类的属性是静态的也就是和我们动态的行为方法相对,它是不变的。因此我们如果对于在类里固定的参数变量就可以先用self来表示。
从函数的语法来看,self在定义的方法里是作为一个形参,其实它的名字可以是任意的变量只是我们习惯性叫self。在类的方法里self是一个普通的参数,按照函数的语法,在调用的时候,必须传递实参值,原因是python的解释器将自动的 调用这个方法的对象作为参数传递给self。
所以类里面所有方法函数里的self形参实际上就是调用这个方法的对象,我们可以通过下面的代码来输出self的值,同时通过self来定义我们类里的实例属性。
1.6属性
通过上面self参数的引出,我们也能知道了self相对于是具体的一个还未定义的对象,那么我们的属性变量在类里定义就不能和在类的外面直接使用 变量名=变量值的形式,而是要用下面的语法来为我们的对象添加属性和获取属性,我们普通的属性其实就是和外面全局变量的属性差不多的语法没什么好说的,直接声明一个值即可。
对象.属性名 = 属性值 # 添加或者修改 对象.属性名 # 获取对象的属性值
重点来说我们的实例属性,例如我们下面的代码(也可以看上面的运行图),可以给我们的Cat类进行实例属性的添加,让之后的tom对象能够有一些静态的值来进行调用。既然我们上面也说到了self其实本身就是类创建的对象,那么对象的属性不就是self.属性名,声明的方法也显而易见是在类的方法当中去进行声明,因为self本身就是在我们对象的方法中去传递的。但是要记住,这里的属性是实例属性!因为它是在方法中声明的,self被看作具体的对象的时候,实例化的对象的属性就是实例属性,要和我们普通的类属性区分开。
class Cat():
def info(self):
self.name = '小猫'
self.age = 18
1.7类,方法和属性小结
其实到这里可能有的人有点晕,我们可以再重新过一遍,class关键字声明的是我们的类,它是一个由很多的方法组成的具有相同特征的抽象的(不能直接用的)统称,这里的方法也就是我们常说的函数。那么我们想要去调用这里面的方法就需要我们去声明(创建)一个对象,对象在这里是具体的它是可以直接使用的,使用的方法就是对象名=类名()。那么抽象的类创建了我们这个具体的对象后,对象就可以调用里面的方法了,语法就是对象.方法名。那么我们的属性呢,属性和方法相比是静态的,属性就是固定的设置好的值,我们在类里的属性就叫类属性,在方法里的属性叫做实例属性,是由它们所在的位置决定的。
2.魔法方法
在python中存在一类方法,它是以两个下划线开头两个下划线结尾,在满足某个条件的情况下,会自动调用,这一类方法 称为是 魔法方法
2.1__init__初始化方法
1.调用时机
在创建对象之后,会自动调用
2.应用场景
初始化对象,给对象添加属性
3.注意事项
-不要写错
-如果 属性是会变化的,则可以将这个属性的值作为参数传递,在创建对象的时候,必须传递实参值
当使用 类名()创建对象时,会自动 执行以下操作:
1.为对象在内存中 分配空间 - 创建对象
2.为对象的属性 设置初始值 - 初始化方法(init)
ps:上面我们在创建单独的方法时候就用到了self.属性名=属性值,是把它写在独立的方法里。如果希望在创建对象的同时,就设置对象的属性的话就可以定义成__init__方法的参数。
2.2__str__方法和__dir__
1.调用时机
使用print(对象) 打印对象的时候,会自动调用
2.如果定义__str__方法,打印的是 方法的返回值
3.注意事项
必须返回一个 字符串
__dir__方法的作用很简单,就是用查看对象内的 所有属性及方法
例如下面的案例:
2.3 __main__
我们在python代码中经常会看到if __name__ == '__main__'
,先说明它的意思如果if __name__ == '__main__'
所在模块是被直接运行的,则该语句下代码块被运行,如果所在模块是被导入到其他的python脚本中运行的,则该语句下代码块不被运行。
在讲解原理之前先补充一个:“程序入口”的概念。如果有学过其他的语言可能知道main()作为主函数一般是程序的入口,但是python是脚本语言,不像编译型语言那些先编译成二进制再运行,解释型的语言会动态逐行解释从脚本的第一行开始运行,没有统一的入口。
python文件的执行方法有两种,一个是直接作为脚本执行;一个是import导入到其他的python脚本中被调用(模块重用)执行不管是直接运行还是导入,我们执行代码的顺序都是从上到下,但是实际过程中我们使用起来并不一定想去执行所有的代码。而if __name__ = '__main__' 的作用就是定义这两种情况执行代码的执行方式,在该语句下的代码在文件作为脚本直接执行情况下才会,import到其他的脚本中就不会执行这里面的代码。
例如,我们先创建一个脚本
pi = 3.1415926
def main():
print("pi:", pi)
main()
在demo1.py文件里定义了一个参数 pi,直接执行该文件输出;创建第二个脚本demo2.py用于计算圆的面积,该文件里边需要用到 demo1.py 文件中的 pi 参数,需要我们从 demo1.py 中把 pi 变量导入到 demo2.py 中
from param import pi
def area_calculate(r):
s = pi * (r ** 2)
return s
def main():
print("The area of the circle: ", area_calculate(2))
main()
最后我们得到的结果是:
pi: 3.1415926 The area of the circle: 12.5663704
但是我们并不想要去执行demo1中的main(),所以我们就可以把它写入__main__中的部分,我们的demo1代码就可以改成
pi = 3.1415926
def main():
print("pi:", pi)
if __name__ == "__main__":
main()
因此demo2就可以不输出pi的值。
总结
这次博文讲了面向对象编程的基本语法和思路,也讲了几个常见的魔法方法,后面会再讲一些的面向对象里的三种特种,和面向对象其他的语法。