面向对象
前言:java , c# 只支持面向对象,python 即支持函数式编程,也支持面向对象编程。
一,函数式编程,面向对象编程
1 ###函数式编程 2 def mail(email,message): 3 print("去发吧!") 4 return True 5 6 mail("alex3714@126.com", "好人") 7 8 9 10 11 ###面向对象:类,对象 12 13 class FOO: 14 # 方法(函数在面向对象中叫方法) 15 def mail(email,message): 16 print("去发吧!") 17 return True 18 19 # 调用 20 21 #1,创建对象,类名() 22 23 # obj = FOO() 24 25 #2, 通过对象去执行方法 26 27 # obj.mail("alex3714@126.com", "好人")
通过以上对比发现面向对象不如函数式编程好。是不是面向对象一无是处呢,接着看哦!
二,类和对象
a, 创建类
class 类名:
def 方法名(self,xxxx): # 注意self 不需要我们去传值,Python自动给其传值
pass
b, 创建对象
对象 = 类名()
c, 通过对象执行方法
对象.方法名(123)
1 # 函数式编程: 2 3 def fetch(host, username, password, sql): 4 pass 5 6 def create(host, username, password, sql): 7 pass 8 9 def remove(host, username, password, ID): 10 pass 11 12 def modify(host, username, password, name): 13 pass 14 15 16 # 面向对象编程: 17 18 class SQLHandLer: #定义类 19 20 def fetch(self, sql): # 定义方法 21 print(self.hhost) 22 print(self.uusername) 23 print(self.pwd) 24 pass 25 26 def create(self, sql): 27 pass 28 29 def remove(self, ID): 30 pass 31 32 def modify(self, name): 33 pass 34 35 obj1 = SQLHandLer() #类对象指针,保存对象是由哪个类创建的,把对象指向某个类。 36 obj1.hhost = "www.example.com" 37 obj1.uusername = "alex" 38 obj1.pwd = "123" 39 # 相当于主机名,用户名,密码封装到对象obj当中 40 41 obj1.fetch("select * from A") 42 # 此时把"select * from A"当作参数传递给fetch中的sql,然后把obj1当作一个整体传 43 #给fetch中的self,因此通过self就可以获取到封装的主机名,用户名,密码 44 45 #结果如下: 46 47 www.example.com 48 alex 49 123 50 select * from A
# 对象和类的关系:对象是由类创建的
小结:
到底什么时候使用面向对象?
如果有一些的函数有共同的参数,可以使用面向对象,把共同的参数一次性进行封装,以后直接去对象中取值即可!
三,self是什么?
self是一个Python会自动给传值的参数。
简单来说,即哪个对象执行方法,self就是谁。
obj1.fetch("select...") self=obj1
obj2.fetch("select...") self=obj2
例子2中self是obj1, 如果要连接另外一个数据库的话,此时就得创建
一个类似的obj2,而此时的self就是obj2
思考:如果上例中有20个数据库,那就需要创建20个对象,将会显得异常的麻烦!怎么办,接着往下看。
四,构造方法
1 class SQLHandLer: 2 def __init__(self, a1, a2, a3): 3 # print("自动执行__int__方法!") 4 self.host = a1 5 self.username = a2 6 self.pwd = a3 7 8 def fetch(self, sql): 9 self.host = "ww.yewu.com" # 在其他的函数中可以对__int__中封装对象相应的值做调用和重新赋值等操作! 10 print(self.host, self.username, self.pwd, sql) 11 pass 12 13 def create(self, sql): 14 pass 15 16 def remove(self, id_number): 17 pass 18 19 def modify(self, name): 20 pass 21 22 obj = SQLHandLer("www.example1.com", "alex", "123") 23 obj.fetch("select * from student") 24 25 26 # 结果如下: 27 28 www.example1.com alex 123 select * from student 29
小结:类中有一个特殊的方法__init__ ,当出现 "类()" 时,__init__ 将会被自动执行。此时无论
出现多少数据库,只需要往SQLHandler中传参数即可!
注意:这里面有一个需要注意的点,就是在类里面,进行函数调用时,不分先后顺序都可以调用得到。
比如,可以在__init__,方法中调用下面的其他如create()等函数。
五,面向对象的三大特性:
- 封装 (面向对象中最最重要的一点!)
- 继承 (比较有用)
- 多态 (这点特性在python中没有太多的意义,这点特性在c#,java这种强类型的语言中比较有用)
六,面向对象之对象中封装对象
常见的类:str,list,dict,tuple,set 这六个python常见的类,我们也可以自定义类。
1 class c1: 2 def __init__(self, name, obj): 3 self.name = name 4 self.obj = obj 5 6 7 class c2: 8 def __init__(self, name, age): 9 self.name = name 10 self.age = age 11 12 def show(self): 13 print(self.name) 14 print("show") 15 16 17 class c3: 18 def __init__(self, a1): 19 self.money = 123 20 self.aaa = a1 21 22 c2_obj = c2("aa", 11) 23 # c2_obj 是c2类型,包含 name = "aa", age = 11 24 25 c1_obj = c1("alex", c2_obj) # ------>把对象当参数传递 26 # c1_obj 是c1类型,,包含 name = "alex", obj = c2_obj 27 28 c3_obj = c3(c1_obj) 29 # c3_obj 是c3类型,包含 money = 123, aaa = c1_obj 30 31 32 # 如何用c3_obj调用 show(),方法 ??? 33 34 c3_obj.aaa.obj.show() # 一定注意去理解哈 35 36 37 # 结果如下: 38 aa 39 show
七,继承性
(python可以多继承,可以单继承,java和C#只能单继承)
-
单继承
1.
1 class F1: # 父类,也叫基类 2 def show(self): 3 print("show") 4 5 def foo(self): 6 print(self.name) 7 8 9 class F2(F1): # 子类,也叫派生类 10 def __init__(self, name): 11 self.name = name 12 13 def bar(self): 14 print("bar") 15 16 def show(self): 17 print("F2.show") 18 19 obj = F2("alex") 20 obj.foo() # 请问这个执行结果会是"alex"吗? 21
答案是肯定的。见下面注意的第二点。
小结:需要注意以下几点?
1,子类只能继承父类,下面的类只能继承上面的类,同样子类也可能变成父类,相对的。
2,子类在继承之后之所以能调用父类的方法,本质上就是相当于把父类中的方法在子类中重写一遍。
3,子类在继承父类之后,如果父类中也有同样的方法,在执行时优先执行自己的方法
2.
1 class S1: 2 def f1(self): 3 self.f2() 4 5 def f2(self): 6 print("S1.f2") 7 8 9 class S2(S1): 10 def f3(self): 11 self.f1() 12 13 def f2(self): 14 print("S2.f2") 15 16 # 判断执行结果,到底会执行哪个f2()????? 17 18 obj1 = S2() # 一定要从根入手,obj1是根据S2创建的 19 obj1.f3() 20 21 obj2 = S1() # 一定要从根入手,obj2是从s1创建的 22 obj2.f1()
结果如下:
S2.f2
S1.f2
分析:可以通过上面注意事项中的第二点来看,也看以通过根来看,观察对象是根据那个类来创建的。这是继承易混淆的点,以后在看源码时会经常碰到类似的问题,其实并不难。
-
多继承
- 没有共同父类的多继承
1 class C0: 2 def f2(self): 3 print("C0.f2") 4 5 class C1: 6 def f2(self): 7 print("C1.f2") 8 pass 9 10 11 class C2(C0): 12 def f1(self): 13 print("C2.f1") 14 pass 15 16 17 class C3(C2, C1): # 谁在前面就就先继承谁(如果C1和C2当中有相同的方法就可以体现出来) 18 def f3(self): 19 pass 20 21 obj = C3() 22 obj.f2()
# 当没有共同的父类的时,谁在前面,会一直向上找,一直找到没有继承。(像C3在继承时,会一直向上找 C3-->C2-->C0 ,实在找不到才会去找C1(一条道路走到黑)
2, 有共同父类的多继承
1 class C_2: 2 def f2(self): 3 print("C_2.f2") 4 pass 5 6 class C_1(C_2): 7 def f5(self): 8 print("C_2.f2") 9 pass 10 11 class C0(C_2): 12 def f6(self): 13 print("C0.f2") 14 15 class C1(C0): 16 def f2(self): 17 print("C1.f2") 18 pass 19 20 class C2(C_1): 21 def f4(self): 22 print("C2.f2") 23 pass 24 25 class C3(C2, C1): # 谁在前面就就先继承谁(如果C1和C2当中有相同的方法就可以体现出来) 26 def f3(self): 27 pass 28 29 obj = C3() 30 obj.f2()
小结:当有共同的父类时,会从前面类顺着继承找到顶端,但不会找到最后的父类,如果还找不到,则会从另一路继承开始找,父类最后执行!
如图所示:C2是他们共同的父类,C3 -->C2--> C_1(不找最后的父类),如果还找不到,则从C1-->C0-->C_2
注意:
在python3+上有共同的父类继承都如上,因为在python3+,所有的类默认继承ojbect类。
但是在python2.7中:
1, 当没有共同的父类时和python3+是一样的,
2, 当有共同的父类时,python2.7默认会前面类顺着继承找到顶端,而且会找到最后的父类。
但是如果让最后的父类继承object类之后,执行顺序和python3+一样。因为在python3+默认
所有的类都继承object类
3, python2.7类分为:经典类和新式类,经典类会一条道走到黑,找到最顶端。而新式类(即继承object)
类之后,和python3+一样
3, 多继承问题的实例
1 class C1: 2 def forever(self): 3 self.run() 4 5 class C2(C1): 6 def __init__(self): 7 pass 8 9 def run(self): 10 self.process() 11 12 def process(self): 13 print("C2.process") 14 15 class C3(C2): 16 def __init__(self): 17 pass 18 19 class C4: 20 def process(self): 21 print("C4_process") 22 23 class C5(C4, C3): 24 pass 25 26 obj = C5() 27 obj.forever() 28 29 30 结果如下: 31 32 C4_process
对执行过程进行分析:
1,首先obj = C5(),这一步就决定:第一步先找执行C5下面的__init__方法,C5下面没有__init__方法,紧接着去找C4下面的__init__方法(也没有),再找C3下面的__init__方法,有并执行。
2,执行obj.forever(), C5(没有forever方法)--> C4(也没有) --> C3(也没有) --> C2(也没有) --> C1(有并执行forever方法,forever下有run()方法,此时的run.self中的self仍为obj,因此从根开始找)--> C5(没有)--> C4(没有) --> C3(没有) --> C2(有并执行,但是此时run()中还有process方法,同上从根开始找) --> C5(没有)--> C4(有,并执行)--> 结束!