zoukankan      html  css  js  c++  java
  • 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.分析结束。

  • 相关阅读:
    云架构系统如何做性能分析?| 实战干货
    1024 程序员日,聊聊升职加薪与职业发展!
    测试面试题集锦(三)| 计算机网络和数据库篇(附答案)
    在线沙龙 | 前端测试技术创新与实践
    测试开发系列课程学员打卡听课细则
    这 5 款实用性能测试工具,你会如何选择?
    618 年中大促!Python 自动化测试训练营立减 1000 元!送接口测试实战课!
    美人
    栀子花开
    朋友别哭
  • 原文地址:https://www.cnblogs.com/xxby/p/5607319.html
Copyright © 2011-2022 走看看