python 面向对象

python 面向对象编程

面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。

面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。

而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。

在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。

  • 面向过程:根据业务逻辑从上到下写垒代码
  • 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
  • 面向对象:对函数进行分类和封装。

ps:Java和C#来说只是支持面向对象编程,而python比较灵活即支持面向对象编程而支持函数式编程

函数式编程与面向对象编程简单对比

函数式编程:
def mail(email,message):
     print('发邮件')
     return True
mail('11111@qq.com','msg')

面向对象编程:类,对象

class Foo:
     #方法
     def mail(self,email,message):
          print('发邮件')
          return True

#调用
1.创建对象,类名()
obj=Foo()
2.通过对象执行方法
obj.mail('11111@qq.com','msg') 
3.类和对象
     a.创建类
          class 方法名(self,xxxx)
               pass
     b.创建对象
          对象=类名()
     c.通过对象执行方法
          对象.方法名(aaaa) 
4.模拟增删改查
 函数式:
     def fetch(host,username,password,sql):
          pass
     def create(host,username,password,sql):
          pass
     def remove(host,username,password,id):
          pass
     def modify(host,username,password,name):
          pass
面向对象:
     class SQLHelpe:
          def fetch( self,host,username,password,sql):
               pass
          def create(self,host,username,password,sql):
               pass
          def remove(self,host,username,password,id):
               pass
          def modify(self,host,username,password,name):
               pass 
     obj = SQLHelper()
     obj = fetch(….) 
简化版本
     class SQLHelpe:
          def fetch(self,sql):
               pass
          def create(self,sql):
               pass
          def remove(self,id):
               pass
          def modify(self,name):
               pass
     #封装到对象里
   obj = SQLHelper()
     obj.hhost = “c1.jd.com"          
     obj.uusername = “xxx"
     obj.pwd = “123"
     obj = fetch("select * from A ")

什么时候用面向对象?当某一些函数具有相同参数时,可以使用面向对象的方式,将参数值一次性的封装到对象,以后去对象中取值即可。

面向对象三大特性

封装、继承和多态。

封装

构造方法__init__:

构造方法__init__:
类()  自动执行类下面的__init__(self)方法
class Foo:
    def __init__(self):
        print('自动执行__init__')
Foo()

执行结果:

自动执行__init__
简单举例:
class SQLHelpe:
      def fetch(self,sql):
           print(self.hhost)
           print(self.uusername)
           print(self.pwd)
           print(sql)
      def create(self,sql):
           pass
      def remove(self,id):
           pass
      def modify(self,name):
           pass
obj = SQLHelpe()
obj.hhost = "c1.jd.com"
obj.uusername = "xxx"
obj.pwd = "123"
obj.fetch("select * from A ")

执行结果:

c1.jd.com
xxx
123
select * from A 

如果有多个对象该怎么办?

class SQLHelpe:
      def fetch(self,sql):
           print(self.hhost)
           print(self.uusername)
           print(self.pwd)
           print(sql)
      def create(self,sql):
           pass
      def remove(self,id):
           pass
      def modify(self,name):
           pass
obj = SQLHelpe()
obj.hhost = "c1.jd.com"
obj.uusername = "xxx"
obj.pwd = "123"
obj1= SQLHelpe()
obj1.hhost = "c2.jd.com"
obj1.uusername = "aaa"
obj1.pwd = "456"

obj.fetch("select * from A ")
print("分割线".center(50,'-'))
obj1.fetch("obj1....")

执行结果:

c1.jd.com
xxx
123
select * from A 
-----------------------分割线------------------------
c2.jd.com
aaa
456
obj1....

这时就要用到类中的构造方法__init__,说__init__之前先要了解一下self是什么鬼?

self是什么?
self是一个形式参数,是python自动会传递值的参数

哪个对象执行方法,self就是谁

封装内容,通过self去调用

class SQLHelpe:
      def __init__(self,host,name,pwd):
          self.host = host
          self.name = name
          self.pwd =pwd
      def fetch(self,sql):
           print(self.host)
           print(self.name)
           print(self.pwd)
           print(sql)
      def create(self,sql):
           pass
      def remove(self,id):
           pass
      def modify(self,name):
           pass
obj = SQLHelpe('www.jd.com','xxx',123)
obj.fetch('select * from A ')
obj1 = SQLHelpe('www.baidu.com','aaa',456)
obj1.fetch('bbbbbb')

执行结果:

www.jd.com
xxx
123
select * from A 
www.baidu.com
aaa
456
bbbbbb

封装的内容也可以通过对象直接去调用

class SQLHelpe:
      def __init__(self,host,name,pwd):
          self.host = host
          self.name = name
          self.pwd =pwd
      def fetch(self,sql):
           print(self.host)
           print(self.name)
           print(self.pwd)
           print(sql)
      def create(self,sql):
           pass
      def remove(self,id):
           pass
      def modify(self,name):
           pass
obj = SQLHelpe('www.jd.com','xxx',123)
obj.fetch('select * from A ')
print(obj.host,obj.name,obj.pwd)

执行结果:

www.jd.com
xxx
123
select * from A 
www.jd.com xxx 123

综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。

对象中封装对象

先来简单的铺垫下

class c1:
    def __init__(self,name,obj):
        self.name = name
        self.obj =obj
    def show(self):
        print('c1 show')
class c2:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def show(self):
        print('c2 show')
c2_obj = c2('c2',20)
c1_obj = c1('c1',c2_obj)
print(c1_obj.name)
print(c1_obj.obj.name)
c1_obj.obj.show()
c1_obj.show()

执行结果:

c1
c2
c2 show
c1 show

此时,将c2_obj作为对象封装到c1里,c1_obj是c1的对象,所以c1_obj.obj = c2_obj

总结:对象里可以封装任意类型的值

稍微复杂点,加点难度:

class c1:
    def __init__(self,name,obj):
        self.name = name
        self.obj =obj
    def show(self):
        print('c1 show')
class c2:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def show(self):
        print('c2 show')
class c3:
    def __init__(self,a1):
        self.money = 123
        self.aaa = a1
c2_obj =c2('c2',20)
c1_obj = c1('c1',c2_obj)
c3_obj = c3(c1_obj)
print(c3_obj.aaa.name)
print(c3_obj.aaa.obj.name)
print('----------')
c3_obj.aaa.show()
c3_obj.aaa.obj.show()

执行结果:

c1
c2
----------
c1 show
c2 show

解析:根据上面的代码,在创建c3类,将c1_obj作为对象封装到c3_obj对象中

通过c3_obj去调c1_obj,c2_obj中的值

此时,

c2_obj是c2类型,”name“=c2,age=20

c1_obj是c1类型,”name“=c1,obj=c2_obj

c3_obj是c3类型,c3_obj.aaa是c1_obj,c1_obj.obj=c2_obj,所以c3_obj.aaa.obj是c2_obj

继承

继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。

简单继承:

class F1:       #父类,基类
    def show(self):
        print('F1.show')
class F2(F1):           #子类,派生类
    def bar(self):
        print('bar')
f2_obj = F2()
f2_obj.bar()
f2_obj.show()

执行结果:

bar
F1.show

F2继承F1后,F1就是父类,F2就是子类,F1也可以叫做基类,F2也可以叫做派生类,父类子类是一对,基类和派生类是一对。

继承后,就相当于:F1的show方法在F2里又写了一遍

class F2(F1):
    def show(self):
        print('F1.show')
    def bar(self):
        print('bar')

加点难度:

class F1:
    def show(self):
        print('F1.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')
class F3(F2):
   pass
f2_obj = F2('pando')
f2_obj.bar()
f2_obj.show()
f2_obj.foo()

执行结果:

bar
F2.show
pando

解析:F1,F2里同时有show方法,子类自己的show方法优先级高于父类的show方法

F2继承F1后,就把F1里的所有方法全部搬到F2里,所以foo方法会被执行

总结:子类继承父类后,即拥有了父类中的所有方法

在加点难度:

class S1:
    def f1(self):
        self.f2()
    def f2(self):
        print('s1-f2')
class S2(S1):
    def f3(self):
        self.f1()
    def f2(self):
        print('s2-f2')
obj = S2()
obj.f3()

aa = S1()
aa.f1()

执行结果:

s2-f2
s1-f2

解析:

S1里有两个方法,f1,f2,S2里有两个方法,f3,f2,S2继承S1

创建S2对象obj,执行obj.f3方法,去S1里找f1方法,f1方法又去找f2方法

那么问题来了,是执行S1的f2方法还是S2的f2方法??

仔细想下,当然是执行S2的f2方法了,S2继承S1后,相当于把S1里的所有方法搬到S2里,而S2自己本身f2方法优先级高于S1的f2方法,所以执行S2的f2方法

总结:

继承以后,每一次找的时候,一旦涉及到self,都回到起点开始找,子类里没有就去父类里找,父类里找不到再去父父类里找 。

直白的说,就是碰到self.xx,就从起点开始找,找到为止,每次碰到self都在起点开始往上一层一层找。

单继承还不够,多继承来了...

 简单的多继承

class C1:
    def f2(self):
        print('c1')
class C2:
    def f2(self):
        print('c2')
class C3(C2,C1):
    def f3(self):
        self.f2()
obj = C3()
obj.f3()

执行结果:

c2

C3继承C2,C1,找f2方法时,从左向右依次开始找,所以找到C2的f2

稍微复杂一点

class C0:
    def f2(self):
        print('c0')
class C1(C0):
    def f999(self):
        print('c1')
class C2:
    def f2(self):
        print('c2')
class C3(C1,C2):
    def f3(self):
        self.f2()
obj = C3()
obj.f3()

执行结果:

c0

解析:

如图所示

C3继承C1,C2后,去找f2,从左开始找,所谓“一条道走到黑,不撞南墙不回头,如果撞了,在换一条道”,所以在C0里找到f2,如果C0里没有,在去C2里找

再复杂一点

class C5:
    def final(self):
        print('C5')
class C2(C5):
    def c2(self):
        print('c2')
class C4(C5):
    def c4(self):
        print('c4')
class C1(C2):
    def c1(self):
        print('c1')
class C3(C4):
    def final(self):
        print('c3')
class C0(C1,C3):
    def c0000(self):
        self.final()
obj = C0()
obj.c0000()

执行结果:

c3

 解析:

如图所示

C0继承C1,C3,

C1继承C2,C2继承C5

C3继承C4,C4继承C5

C0找final方法,C5,C3里都有final方法

C0从做左面的C1开始往上一层一层找,找到C2还没找到final,就不在继续找了,开始从右面的C3开始找

总结:当有共同父类时,左面的找到父类前,还没找到final的话,开始从右面开始找,直到找到为止。

注:只有Python3是这样的,Python2还分经典类和新式类,后续再讲。

继承之解析socket源码

 先来点铺垫吧,如图

如图所示,

A类继承B类和C类

C类继承D类

D类继承E类

创建对象

obj=A()

obj.forever()

执行obj.forever()方法,

1.首先A()代表先执行A类的__init__方法,A类里没有,去B类里找,B类里也没有,C类里有,执行C类里的__init__方法。

2.执行完A()后,该执行obj.forever()方法,B类里没有,从C类里往上找,在E类里找到了,然后去找self.run()方法。

3.碰到self从头开始找,在从A类开始找,B类里没有,从C类开始往上找,在D类里找到,run()方法下面执行self.process()。

4.因为有self,所以再从头开始找,去B类里找,B类有process()方法,所以找到了,程序结束。

开始分析socket源码探究类的寻找过程

import socketserver

obj = socketserver.ThreadingTCPServer()

obj.serve_forever()

首先分析ThreadingTCPServer(),因为socketserver是个类,所以ThreadingTCPServer()有可能是一个函数或者是一个类。

如果ThreadingTCPServer()是一个函数则直接执行该函数,如果ThreadingTCPServer()是一个类,则直接执行该类的__init__方法。

查看源码,发现它是一个类,这个类下面没有内容,但是它继承了两个其他的类,一个是ThreadingMixIn,另一个是 TCPServer。

1.ThreadingTCPServer()这个类是一个空类,里面没有__init__方法,所以优先去ThreadingMixIn里找。

2.ThreadingMixIn也没有__init__方法,但是里面有2个方法,一个是process_request_thread,另一个是process_request。所以去下一个类TCPServer里找__init__方法。

3.这个类里有__init__方法,所以先执行__init__方法。__init__执行完毕后,就相当于obj = socketserver.ThreadingTCPServer()这段代码执行完毕,

然后去执行obj.serve_forever()这段代码。

4.执行obj.serve_forever(),还要去ThreadingMixIn和TCPServer这两个里找serve_forever()方法。左面的ThreadingMixIn类里没有这个方法,然后再去右面的TCPServer里找。

5.在TCPServer里也没有serve_forever()方法,在继续去它的父类BaseServer里找。

6.找到serve_forever(),我们看到里面有一个self._handle_request_noblock()方法,下面我们去找这个方法,碰到self,又应该从头开始找。

ThreadingMixIn里没有,我们去TCPServer里找,TCPServer里也没有,然后去它的父类BaseServer里找。

7.找到_handle_request_noblock()方法,发现里面又有一个self.process_request,此时我们发现左边还有一个process_request方法,但是不能执行

这个process_request方法,因为这个process_request方法前还self。我们又要从头开始找。

8.回到步骤1,从头开始找,发现在ThreadingMixIn里有process_request方法,所以最终执行的还是ThreadingMixIn里的process_request方法,

而不是BaseServer里的process_request方法。

9.分析结束。

原文地址:https://www.cnblogs.com/xxby/p/5607319.html