Python基础—面向对象(初级篇)
一、什么是面向对象编程
面向对象编程(Object Oriented Programming,OOP,面向对象程序设计),python语言比较灵活即支持面向对象编程也支持面向函数式编程。
面向过程编程:根据业务逻辑从上到下写,一层一层的垒起来的代码;
函数式编程:将某个功能代码封装到函数中,日后便无需重复编写,仅调用函数即可;
面向对象编程:对函数进行分类和封装吗,让'开发'更快更好更强。。。
下面我们就先复习一下面向过程编程和函数式编程的编写过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
while True : if cpu利用率 > 90 % : #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 if 硬盘使用空间 > 90 % : #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 if 内存占用 > 80 % : #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 |
上面的代码是典型的面向过程编程的例子,随着我们学习的后面学到了函数式编程,将上面的代码就优化成了下面这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
def 发送邮件(内容) #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 while True : if cpu利用率 > 90 % : 发送邮件( 'CPU报警' ) if 硬盘使用空间 > 90 % : 发送邮件( '硬盘报警' ) if 内存占用 > 80 % : 发送邮件( '内存报警' ) |
二、创建类和对象
类就是一个模版,模板里可以包含多个函数,函数里实现一些功能。
对象则是根据模板创建的实例,通过实例对象可以执行类中的函数。
1
2
3
4
5
|
class SQLHelper: #创建类 def fetch( self ,sql): #创建类中的函数 obj = SQLHelper() #根据SQLHelper创建对象obj |
class是关键字,表示类,SQLHelper是类的名称;
函数中的self为特殊参数,相当于obj传入到函数中,在类中必填
创建对象,就是在类名称后面加括号即可;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
#函数时编程 def fetch(host,username,passwd,sql): pass def create(host,username,passwd,sql): pass def remvoe(host,username,passwd,sql): pass def modify(host,username,passwd,sql): pass #在函数式编程时,执行每个方法的时候都要去调用一次这些函数 #面向对象编程 class SQLHelper: def fetch( self ,sql): #在面向对象编程时,这里的self就相当于obj,可以定义好,供类里方法使用 print (sql) def create( self ,sql): pass def remove( self ,sql): pass def modify( self ,sql): pass obj = SQLHelper() #根据类创建对象obj obj.hhost = "co.salt.com" obj.uusername = 'jack' obj.pwd = '123' obj.fetch( "select * from A" ) #执行类里面的fetch方法 |
从上面的例子看出,使用函数式编程和面向对象编程方式来执行一个'方法'时函数要比面向对象简便。
面向对象编程:需要先创建对象,通过对象来执行方法
函数式编程:直接执行函数
观察上述对比答案则是肯定的,然而并非绝对,场景的不同适合其的编程方式也不同,函数式编程多用于各个函数之间是独立且无共用的数据,当某一些函数具有相同参数时,可以使用面向对象编程,将参数值一次性的封装到对象,以后去对象中取值即可。
三、面向对象三大特性
面向对象有三大特性分别是: 封装、继承和多态。下面就分别介绍一下具体用法:
(一)、封装特性
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。下面我们分两步介绍面向对象的封装:
1、将内容封装到某处
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#首先创建类 class SQLHelper: def __init__( self ,a1,a2,a3): #__init__类中特殊的方法,称为构造方法;根据类创建对象时自动执行 self .hhost = a1 self .uusername = a2 self .passwd = a3 def fetch( self ,sql): print (sql) #自动执行SQLHelper类的__init__方法 obj1 = SQLHelper( 'C1.salt.com' , 'jack' , 123 ) #将'C1.salt.com,jack,123'封装到self中的a1,a2,a3属性中 |
上面的例子中,self是一个形式参数,当执行obj1 = SQLHelper('C1.salt.com','alex',123)s时,self等于obj1;所以内容其实被封装到了对象obj1中,每个对象中的属性都会先存在内存里,类似下面这种方式保存:
2、从某处调用被封装的内容
调用被封装的内容时,有两种情况:1、通过对象直接调用;2、通过self间接调用。
上图展示了对象obj1在内存中保存方式,根据保存格式可以如此调用被封装的内容:对象.属性名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class Foo: def __init__( self , name, age): self .name = name self .age = age def detail( self ): print self .name print self .age obj1 = Foo( 'haifeng' , 18 ) obj1.detail() # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 haifeng ;self.age 是 18 ddj2 = Foo( 'jack' , 73 ) obj2.detail() # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 jack ; self.age 是 78 |
从上面的例子可以看出,对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接取封装的内容。
3、多层封装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
class c1: def __init__( self ,name,obj): self .name = name self .obj = obj #这里的obj就是c2_obj class c2: def __init__( self ,name,age): self .name = name self .age = age def show( self ): print ( self .name) return 123 class c3: def __init__( self ,a1): self .money = 123 self .aaa = a1 c2_obj = c2( 'jack' , 18 ) c1_obj = c1( 'eric ,c2_obj) #将c2_obj当作参数传入c1_obj print (c1_obj.obj.age) #这里打印的是age为18 c3_obj = c3(c1_obj) print (c3_obj.aaa.obj.name) #取到Jack这个用户名 c3_obj.aaa.obj.show() ret = c3_obj.aaa.obj.show() #使用c3_obj执行show方法 print (ret) #打印返回值 jack None #打印结果时值为None,这是因为上面的函数没有定义返回值 |
简单的解释一下上面的程序,就是一个多层封装的一个例子,首先定义了三个类,分别封装了不同的内容:
c1_obj :封装了name='eric',obj = c2_obj
c2_obj :封装了name='jack',age=18
c3_obj :封装了 c1_obj这个对象
当我们要想通过c1_obj来获取age属性的时候,就会先去找c1_obj的obj属性,obj属性有对应的是c2_obj对象,在c2_obj对象中找到age属性,获取方法就是:c1_obj.obj.age
如果我们想通过c3_obj来执行show()方法的时候,首先我们看c3_obj有两个属性,money=123,aaa=c1_obj,没有show()方法,然后我们去找c1_obj对象。c1_obj对象中也没有show()方法,有obj=c2_obj,我们再去找c2_obj对象,c2_obj对象中有show()方法,执行show()方法:c3_obj.aaa.obj.show()
(二)、继承特性
继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class F1: #父类(基类) def show( self ): print ( 'show' ) def foo( self ): print ( self .name) class F2(F1): #子类(派生类):子类继承父类,即拥有了父类中所有的方法 def __init__( self ,name): self .name = name def bar( self ): print ( 'bar' ) def show( self ): #如果子类和父类同时定义了一个方法,会优先执行子类的方法 print ( 'F2.show' ) obj = F2( 'jack' ) obj.foo() #执行父类中的方法,这里F2会继承F1的foo方法打印jack |
那么问题来了,python是否可以继承多个类?如果可以继承了多个类每个类中都定了相同的函数,那么哪一个会被使用呢?
带着这两个问题我们继续往下看,在python中类可以继承多个类,Java和C#中则只能继承一个类;如果python类继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先
那么什么是深度优先和广度优选呢,下面同两张图和两个例子来分别介绍一下:
1、深度优先,在类中由于可以定义多个类,在类()最左边的那个类优先继承。
在python2.*中:
当类是经典类时,多继承情况下,会按照深度优先方式查找;
当类时新式类时,多继承情况下,会按照广度优先方式查找。
在python3中只有新式类,没有经典类了。
那么什么是经典类,什么是新式类呢??
顾名思义,一个老一个新,新的包含了更多的功能,也是之后推荐的写法,从写法上区分的话,如果当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。
obj类是python内部定义的最顶层的基类,它是所有新式类的父类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
############################################# class C1: #C1是经典类 pass class C2(C1): #C2是经典类 pass ############################################# class N1( object ): #N1是新式类 pass class N2(N1): #N2是新式类 pass #如果从子类的角度看,它的父类的父类的父类....其中任何一个继承了object,那么它就是新式类 |
下面举个经典类的多继承的例子,方便大家理解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
class F0: def bar( self ): print 'F0.bar' class F1(F0): def bar( self ): print 'F1.bar' class F2(F0): def bar( self ): print 'F2.bar' class F3(F1, F2): def bar( self ): print 'F3.bar' obj = F3() obj.bar() # 执行obj.bar方法时 # 首先去F3类中查找,如果F3类中没有,则继续去F1类中找,如果F1类中么有,则继续去F0类中找,如果F0类中么有,则继续去F2类中找,如果还是未找到,则报错 # 所以,查找顺序:F3 --> F1 --> F0 --> F2 # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了 |
在上面的例子中,如果父类中,有self就回到定义对象的位置重新查找,切记。
2、广度优先:
下面举个新式类的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
class F0( object ): def bar( self ): print 'F0.bar' class F1(F0): def bar( self ): print 'F1.bar' class F2(F0): def bar( self ): print 'F2.bar' class F3(F1, F2): def bar( self ): print 'F3.bar' obj = F3() obj.bar() # 执行bar方法时 # 首先去F3类中查找,如果F3类中没有,则继续去F1类中找,如果F1类中么有,则继续去F2类中找,如果F2类中也没有,则继续去F0类中找,如果还是未找到,则报错 # 所以,查找顺序:F3 --> F1 --> F2 --> F0 |
(三)、多态特性
静态语言 vs 动态语言
class Animal(object):
def run(self):
print(Animal is running...) class Dog(Animal):
def run(self):
print(Dog is running...) class Cat(Animal):
def run(self):
print(Cat is running...) obj = Dog()
obj.run()
定义动物类
对于静态语言(例如:java、c#)来说:如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则将无法调用run()方法;
对于python这样的动态语言来说: 则不一定需要传入Animal类型,我们只需要保证传入的对象有一个run()方法就可以了,如上例。
这就是动态语言的"鸭子类型",它并不要求严格的继承体系,一个对象只要"看起来像鸭子,那它就可以被看做是鸭子"。
今天主要介绍了什么是面向对象编程,创建类和方法以及类的三大特性,类还有很多高级的用法,会在以后介绍给大家,请持续关注。
Python基础—面向对象(初级篇)的更多相关文章
- Python 基础 面向对象之二 三大特性
Python 基础 面向对象之二 三大特性 上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员.成 ...
- python基础——面向对象编程
python基础——面向对象编程 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的 ...
- NSIS安装制作基础教程[初级篇], 献给对NSIS有兴趣的初学者
NSIS安装制作基础教程[初级篇], 献给对NSIS有兴趣的初学者 作者: raindy 来源:http://bbs.hanzify.org/index.php?showtopic=30029 时间: ...
- python基础——面向对象进阶下
python基础--面向对象进阶下 1 __setitem__,__getitem,__delitem__ 把对象操作属性模拟成字典的格式 想对比__getattr__(), __setattr__( ...
- python基础——面向对象进阶
python基础--面向对象进阶 1.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 ...
- python基础——面向对象的程序设计
python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...
- python基础--面向对象基础(类与对象、对象之间的交互和组合、面向对象的命名空间、面向对象的三大特性等)
python基础--面向对象 (1)面向过程VS面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. ...
- python 面向对象初级篇
Python 面向对象(初级篇) 概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发" ...
- Python基础—面向对象(进阶篇)
通过上一篇博客我们已经对面向对象有所了解,下面我们先回顾一下上篇文章介绍的内容: 上篇博客地址:http://www.cnblogs.com/phennry/p/5606718.html 面向对象是一 ...
随机推荐
- Jquery ajax json 值回传不了
今天调试系统的时候,MVC 框架下调用ajax 值,回传的json值获取不到,后来发现竟然是服务没开,郁闷不已,留个截图,做个纪念.
- openstack dnsmasq调试
- Django day 38 结算中心,支付中心,计算价格方法
一:结算中心 二:支付中心 三:计算价格方法
- HDU 5514 欧拉函数应用
前置技能: <=i且与i互质的数的和是phi(i)*i/2 思路: 显然每个人的步数是gcd(a[i],m) 把m的所有因数预处理出来 1~m-1中的每个数 只会被gcd(m,i)筛掉一遍 // ...
- 自动构造词法分析器的步骤——正规式转换为最小化DFA
正规式-->最小化DFA 1.先把正则式-->NFA(非确定有穷自动机) 涉及一系列分解规则 2.再把NFA通过"子集构造法"-->DFA 通过子集构造法将NFA ...
- 平方分割poj2104K-th Number
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 59798 Accepted: 20879 Ca ...
- 流式套接字(SOCK_STREAM),数据报套接字 (SOCK_DGRAM) 的比较
1.流式套接字 使用这种套接字时,数据在客户端是顺序发送的,并且到达的顺序是一致的.比如你在客户端先发送1,再发送2,那么在服务器端的接收顺序是先接收到1,再接收到2,流式套接字是可靠的,是面向连接的 ...
- python中os模块中文帮助
python中os模块中文帮助 python中os模块中文帮助文档文章分类:Python编程 python中os模块中文帮助文档 翻译者:butalnd 翻译于2010.1.7——2010.1.8 ...
- 树莓派连接arduino(USB串口通讯)
2018-06-0115:12:19 https://blog.csdn.net/song527730241/article/details/50884890 重要步骤 查看端口:(ttyUSB0或 ...
- ci框架中model简单的mysql操作
<?php class SingerModel extends CI_Model { function SingerModel() { //会将数据库对象赋值给CI_Controller的db属 ...