面向对象基础篇
面向对象的基本格式
1 # ###### 定义类 ###### 2 class 类名: 3 def 方法名(self,name): 4 print(name) 5 return 123 6 def 方法名(self,name): 7 print(name) 8 return 123 9 def 方法名(self,name): 10 print(name) 11 return 123 12 # ###### 调用类中的方法 ###### 13 # 1.创建该类的对象 14 obj = 类名() 15 # 2.通过对象调用方法 16 result = obj.方法名('alex') 17 print(result)
应用场景:遇到很多函数,需要给函数进行归类和划分
创建类与对象
面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。
类就是一个模板,模板里可以包含多个函数,函数里实现一些功能
对象则是根据模板创建的实例,通过实例对象可以执行类中的函数
- class是关键字,表示类
- 创建对象,类名称后加括号即可
ps:类中的函数第一个参数必须是self(详细见:类的三大特性之封装)
类中定义的函数叫做 “方法”
1 # 创建类 2 class foo: 3 4 def bar(self): 5 print 'bar' 6 7 def hello(self, name): 8 print 'i am %s' %name 9 10 # 根据类foo创建对象obj 11 obj = foo() 12 obj.bar() #执行bar方法 13 obj.hello('wupeiqi') #执行hello方法
面向对象的三大特性
面向对象的三大特性是指:封装、继承和多态。
一、封装
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
所以,在使用面向对象的封装特性时,需要:
- 将内容封装到某处
- 从某处调用被封装的内容
第一步:将内容封装到某处
self 是一个形式参数,当执行 obj1 = foo('wupeiqi', 18 ) 时,self 等于 obj1
当执行 obj2 = foo('alex', 78 ) 时,self 等于 obj2
所以,内容其实被封装到了对象 obj1 和 obj2 中,每个对象中都有 name 和 age 属性,在内存里类似于下图来保存。
第二步:从某处调用被封装的内容
调用被封装的内容时,有两种情况:
- 通过对象直接调用
- 通过self间接调用
1、通过对象直接调用被封装的内容
上图展示了对象 obj1 和 obj2 在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名
1 class foo: 2 3 def __init__(self, name, age): 4 self.name = name 5 self.age = age 6 7 obj1 = foo('wupeiqi', 18) 8 print obj1.name # 直接调用obj1对象的name属性 9 print obj1.age # 直接调用obj1对象的age属性 10 11 obj2 = foo('alex', 73) 12 print obj2.name # 直接调用obj2对象的name属性 13 print obj2.age # 直接调用obj2对象的age属性
2、通过self间接调用被封装的内容
执行类中的方法时,需要通过self间接调用被封装的内容
1 class foo: 2 3 def __init__(self, name, age): 4 self.name = name 5 self.age = age 6 7 def detail(self): 8 print self.name 9 print self.age 10 11 obj1 = foo('wupeiqi', 18) 12 obj1.detail() # python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18 13 14 obj2 = foo('alex', 73) 15 obj2.detail() # python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 alex ; self.age 是 78
举个例子(面向对象与面向函数)
练习一:在终端输出如下信息
- 小明,10岁,男,上山去砍柴
- 小明,10岁,男,开车去东北
- 小明,10岁,男,最爱大保健
- 老李,90岁,男,上山去砍柴
- 老李,90岁,男,开车去东北
- 老李,90岁,男,最爱大保健
- 老张...
面向函数编程
1 def kanchai(name, age, gender): 2 print "%s,%s岁,%s,上山去砍柴" %(name, age, gender) 3 4 5 def qudongbei(name, age, gender): 6 print "%s,%s岁,%s,开车去东北" %(name, age, gender) 7 8 9 def dabaojian(name, age, gender): 10 print "%s,%s岁,%s,最爱大保健" %(name, age, gender) 11 12 13 kanchai('小明', 10, '男') 14 qudongbei('小明', 10, '男') 15 dabaojian('小明', 10, '男') 16 17 18 kanchai('老李', 90, '男') 19 qudongbei('老李', 90, '男') 20 dabaojian('老李', 90, '男') 21 22 函数式编程
class foo: def __init__(self, name, age ,gender): self.name = name self.age = age self.gender = gender def kanchai(self): print "%s,%s岁,%s,上山去砍柴" %(self.name, self.age, self.gender) def qudongbei(self): print "%s,%s岁,%s,开车去东北" %(self.name, self.age, self.gender) def dabaojian(self): print "%s,%s岁,%s,最爱大保健" %(self.name, self.age, self.gender) xiaoming = foo('小明', 10, '男') xiaoming.kanchai() xiaoming.qudongbei() xiaoming.dabaojian() laoli = foo('老李', 90, '男') laoli.kanchai() laoli.qudongbei() laoli.dabaojian() 面向对象
继承
继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。
例如:
猫可以:喵喵叫、吃、喝、拉、撒
狗可以:汪汪叫、吃、喝、拉、撒
如果我们要分别为猫和狗创建一个类,那么就需要为 猫 和 狗 实现他们所有的功能,如下所示:
class 猫: def 喵喵叫(self): print '喵喵叫' def 吃(self): # do something def 喝(self): # do something def 拉(self): # do something def 撒(self): # do something class 狗: def 汪汪叫(self): print '喵喵叫' def 吃(self): # do something def 喝(self): # do something def 拉(self): # do something def 撒(self): # do something 伪代码
所以,对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。
注:除了子类和父类的称谓,你可能看到过 派生类 和 基类 ,他们与子类和父类只是叫法不同而已。
学习了继承的写法之后,我们用代码来是上述阿猫阿狗的功能:
class animal: def eat(self): print "%s 吃 " %self.name def drink(self): print "%s 喝 " %self.name def shit(self): print "%s 拉 " %self.name def pee(self): print "%s 撒 " %self.name class cat(animal): def __init__(self, name): self.name = name self.breed = '猫' def cry(self): print '喵喵叫' class dog(animal): def __init__(self, name): self.name = name self.breed = '狗' def cry(self): print '汪汪叫' # ######### 执行 ######### c1 = cat('小白家的小黑猫') c1.eat() c2 = cat('小黑的小白猫') c2.drink() d1 = dog('胖子家的小瘦狗') d1.eat() 代码实例
那么问题又来了,多继承呢?
- 是否可以继承多个类
- 如果继承的多个类每个类中都定了相同的函数,那么那一个会被使用呢?
1、python的类可以继承多个类,java和c#中则只能继承一个类
2、python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先
- 当类是经典类时,多继承情况下,会按照深度优先方式查找
- 当类是新式类时,多继承情况下,会按照广度优先方式查找
经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果 当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。
class d: def bar(self): print 'd.bar' class c(d): def bar(self): print 'c.bar' class b(d): def bar(self): print 'b.bar' class a(b, c): def bar(self): print 'a.bar' a = a() # 执行bar方法时 # 首先去a类中查找,如果a类中没有,则继续去b类中找,如果b类中么有,则继续去d类中找,如果d类中么有,则继续去c类中找,如果还是未找到,则报错 # 所以,查找顺序:a --> b --> d --> c # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了 a.bar() 经典类多继承
class d(object): def bar(self): print 'd.bar' class c(d): def bar(self): print 'c.bar' class b(d): def bar(self): print 'b.bar' class a(b, c): def bar(self): print 'a.bar' a = a() # 执行bar方法时 # 首先去a类中查找,如果a类中没有,则继续去b类中找,如果b类中么有,则继续去c类中找,如果c类中么有,则继续去d类中找,如果还是未找到,则报错 # 所以,查找顺序:a --> b --> c --> d # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了 a.bar() 新式类多继承
经典类:首先去a类中查找,如果a类中没有,则继续去b类中找,如果b类中么有,则继续去d类中找,如果d类中么有,则继续去c类中找,如果还是未找到,则报错
新式类:首先去a类中查找,如果a类中没有,则继续去b类中找,如果b类中么有,则继续去c类中找,如果c类中么有,则继续去d类中找,如果还是未找到,则报错
注意:在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
三、多态
pyhon不支持java和c#这一类强类型语言中多态的写法,但是原生多态,其python崇尚“鸭子类型”。
class f1: pass class s1(f1): def show(self): print 's1.show' class s2(f1): def show(self): print 's2.show' # 由于在java或c#中定义函数参数时,必须指定参数的类型 # 为了让func函数既可以执行s1对象的show方法,又可以执行s2对象的show方法,所以,定义了一个s1和s2类的父类 # 而实际传入的参数是:s1对象和s2对象 def func(f1 obj): """func函数需要接收一个f1类型或者f1子类的类型""" print obj.show() s1_obj = s1() func(s1_obj) # 在func函数中传入s1类的对象 s1_obj,执行 s1 的show方法,结果:s1.show s2_obj = s2() func(s2_obj) # 在func函数中传入ss类的对象 ss_obj,执行 ss 的show方法,结果:s2.show python伪代码实现java或c#的多态
总结
以上就是本节对于面向对象初级知识的介绍,总结如下:
- 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用
- 类 是一个模板,模板中包装了多个“函数”供使用
- 对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数
- 面向对象三大特性:封装、继承和多态
上一篇: php xml常用函数的集合(比较详细)
下一篇: PHP设计模式之结构模式的深入解析
推荐阅读