面向对象编程
面向过程编程:根据业务逻辑从上到下写代码,主要突出在流程上
函数式编程:将某些功能封装在函数里,日后不用重复编写,仅调用函数即可
面向对象编程:对函数进行分类和封装,让开发“更快,更好,更强”
面向过程编程最易被初学者接受,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,即:将之前实现的代码块复制到现需功能处。
创建类和对象
面向对象编程是一种编程范式,此编程方式的落地需要使用‘类’和‘对象’来实现,面向对象编程其实就是对‘类’和‘对象’的使用
类就是一个模板,模板里面可以包含多个函数,函数里实现一些功能
对象则是根据模板创建的实例,通过实例对象可以执行类中的函数
class是关键字,表示类
创建一个对象在类名后面加括号即可
1 #创建类(object代表基类,最大的类 包括万物)
2 classDog(object):3 defrun(self):4 print('run')5
6 defwoof(self):7 print('woof')8
9 #创建对象
10 dog =Dog()11 dog.run() #执行run方法
12 dog.woof() #执行woof方法
面向对象的三大特征
面向对象的三大特性是指:封装、继承和多态。
一、封装
封装,就是把内容封装在某个地方,以后再去调用被封在某处的内容
所以,在使用封装特性时,需要:
1、将内容封装在某处
2、调用某处的被封装内容
将内容封装到某处
class Foo(object): #创建一个Foo类 类名一般首字母大写
def __init__(self, name, age): #__init__为构造方法,根据类创建对象时自动执行
self.name = name #self 为形式参数 当执行 obj1 = Foo('wupeiqi', 18 ) 时,self 等于 obj1
self.age = age #当执行 obj2 = Foo('alex', 78 ) 时,self 等于 obj2
#根据Foo创建对象#自动执行Foo类的__init__方法
obj1 = Foo('huihui', 16) #将huihui和18封装到obj1的name和age属性中
#根据Foo创建对象#自动执行Foo类的__init__方法
obj2 = Foo('zhowhen', 18) #将zhowhen和18封装的obj2的name和age属性中
内容被封装到了对象obj1和obj2中,每个对象中都有name和age属性,在内存里类似于下图保存。
调用某处的被封装内容
调用被封装的内容时,有两种情况:
通过对象直接调用
通过self间接调用
1、通过对象直接调用
classFoo(object):def __init__(self, name, age):
self.name=name
self.age=age
obj1= Foo('huihui', 18)print(obj1.name) #直接调用obj1对象的name属性
print(obj1.age) #直接调用obj1对象的age属性
obj2= Foo('zhow', 20)print(obj2.name) #直接调用obj2对象的name属性
print(obj2.age) #直接调用obj2对象的age属性
2、通过self间接调用被封装的内容
执行类中的方法时,需要通过self间接调用被封装的内容
classFoo(object):def __init__(self, name, age):
self.name=name
self.age=agedefdetail(self):print(self.name)print(self.age)
obj1= Foo('huihui', 18)
obj1.detail()#python默认会把obj1传给self参数,所有此时方法内部的self=obj1
#即self.name<==>obj1.name是huihui self.age<==>obj1.age是18
obj2= Foo('zhowhen', 20)
obj2.detail()#python默认会把obj2传给self参数,所有此时方法内部的self=obj2
#即self.name<==>obj2.name是zhowhen self.age<==>obj2.age是20
综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。
二、继承
面向对象中的继承跟现实中的继承相同,即:子可以继承父的内容;
例如:
猫:跑,喵喵叫,吃饭
狗:跑,旺旺叫,吃饭
可以看出猫和狗有共同的行为:跑,吃饭
所以我们可以创建一个父类,里面有跑和吃饭,猫和狗只要继承了父类就也同时有个跑和吃饭
示例如下:
classAnimal(object):defrun(self):print('%s 在跑' %self.name)defeat(self):print('%s 在吃饭' %self.name)classDog(Animal):def __init__(self, name):
self.name=namedefcall(self):print('%s旺旺叫' %self.name)classCat(Animal):def __init__(self, name):
self.name=namedefcall(self):print('%s喵喵叫' %self.name)
c1= Cat('小红的小花猫')
d1= Dog('小明的哈巴狗')
c1.run()
d1.eat()
所以,对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。
注:除了子类和父类的称谓,你可能看到过 派生类 和 基类 ,他们与子类和父类只是叫法不同而已。
so,是否可以继承多个呢?
yes,python的类可以继承多个类,Java和C#只能继承一个类
python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是深度优先和广度优先
当类是经典类时,多继承情况下,会按照深度优先方式查找
当类是新式类时,多继承情况下,会按照广度优先方式查找
经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果 当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。
python3中都是新式类
1 classD(object):2
3 defbar(self):4 print('D.bar')5
6
7 classC(D):8
9 defbar(self):10 print('C.bar')11
12
13 classB(D):14
15 defbar(self):16 print('B.bar')17
18
19 classA(B, C):20
21 defbar(self):22 print('A.bar')23
24 a =A()25 #执行bar方法时
26 #首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
27 #所以,查找顺序:A --> B --> C --> D
28 #在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
29 a.bar()
注意:在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
三、多态
Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,其Python崇尚“鸭子类型”。
1 classF1:2 pass
3
4
5 classS1(F1):6
7 defshow(self):8 print 'S1.show'
9
10
11 classS2(F1):12
13 defshow(self):14 print 'S2.show'
15
16
17 #由于在Java或C#中定义函数参数时,必须指定参数的类型
18 #为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
19 #而实际传入的参数是:S1对象和S2对象
20
21 defFunc(F1 obj):22 """Func函数需要接收一个F1类型或者F1子类的类型"""
23
24 printobj.show()25
26 s1_obj =S1()27 Func(s1_obj) #在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show
28
29 s2_obj =S2()30 Func(s2_obj) #在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show
View Code
1 classF1:2 pass
3
4
5 classS1(F1):6
7 defshow(self):8 print 'S1.show'
9
10
11 classS2(F1):12
13 defshow(self):14 print 'S2.show'
15
16 defFunc(obj):17 printobj.show()18
19 s1_obj =S1()20 Func(s1_obj)21
22 s2_obj =S2()23 Func(s2_obj)
View Code
类和对象在内存中是如何保存?