• doc


      一、什么是面向对象编程

          面向对象编程(Object Oriented Programming,OOP,面向对象程序设计),python语言比较灵活即支持面向对象编程也支持面向函数式编程。

    •    面向过程编程:根据业务逻辑从上到下写,一层一层的垒起来的代码;

    •    函数式编程:将某个功能代码封装到函数中,日后便无需重复编写,仅调用函数即可;

    •    面向对象编程:对函数进行分类和封装吗,让'开发'更快更好更强。。。 

     下面我们就先复习一下面向过程编程和函数式编程的编写过程:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    while True
        if cpu利用率 > 90%:
            #发送邮件提醒
            连接邮箱服务器
            发送邮件
            关闭连接
      
        if 硬盘使用空间 > 90%:
            #发送邮件提醒
            连接邮箱服务器
            发送邮件
            关闭连接
      
        if 内存占用 > 80%:
            #发送邮件提醒
            连接邮箱服务器
            发送邮件
            关闭连接

    上面的代码是典型的面向过程编程的例子,随着我们学习的后面学到了函数式编程,将上面的代码就优化成了下面这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def 发送邮件(内容)
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接
      
    while True
      
        if cpu利用率 > 90%:
            发送邮件('CPU报警')
      
        if 硬盘使用空间 > 90%:
            发送邮件('硬盘报警')
      
        if 内存占用 > 80%:
            发送邮件('内存报警')

     二、创建类和对象

          类就是一个模版,模板里可以包含多个函数,函数里实现一些功能。

          对象则是根据模板创建的实例,通过实例对象可以执行类中的函数。

    1
    2
    3
    4
    5
    class SQLHelper:            #创建类
     
         def fetch(self,sql):   #创建类中的函数
     
    obj = SQLHelper()           #根据SQLHelper创建对象obj
    •  class是关键字,表示类,SQLHelper是类的名称;

    • 函数中的self为特殊参数,相当于obj传入到函数中,在类中必填

    • 创建对象,就是在类名称后面加括号即可;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #函数时编程
    def fetch(host,username,passwd,sql):
         pass
    def create(host,username,passwd,sql):
         pass
    def remvoe(host,username,passwd,sql):
         pass
    def modify(host,username,passwd,sql):
         pass
    #在函数式编程时,执行每个方法的时候都要去调用一次这些函数
     
    #面向对象编程
    class SQLHelper:
         def fetch(self,sql):    #在面向对象编程时,这里的self就相当于obj,可以定义好,供类里方法使用
             print(sql)
         def create(self,sql):
             pass
         def remove(self,sql):
             pass
         def modify(self,sql):
             pass
    obj = SQLHelper()           #根据类创建对象obj
    obj.hhost = "co.salt.com"  
    obj.uusername = 'jack'
    obj.pwd = '123'
    obj.fetch("select * from A"#执行类里面的fetch方法

    从上面的例子看出,使用函数式编程和面向对象编程方式来执行一个'方法'时函数要比面向对象简便。

           面向对象编程:需要先创建对象,通过对象来执行方法

          函数式编程:直接执行函数 

    观察上述对比答案则是肯定的,然而并非绝对,场景的不同适合其的编程方式也不同,函数式编程多用于各个函数之间是独立且无共用的数据,当某一些函数具有相同参数时,可以使用面向对象编程,将参数值一次性的封装到对象,以后去对象中取值即可。

     三、面向对象三大特性

         面向对象有三大特性分别是: 封装、继承和多态。下面就分别介绍一下具体用法:

        (一)、封装特性

    封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。下面我们分两步介绍面向对象的封装:

        1、将内容封装到某处

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #首先创建类
    class SQLHelper:
         def __init__(self,a1,a2,a3):         #__init__类中特殊的方法,称为构造方法;根据类创建对象时自动执行
             self.hhost=a1
             self.uusername=a2
             self.passwd=a3
     
         def fetch(self,sql):
             print(sql)
     
    #自动执行SQLHelper类的__init__方法
    obj1=SQLHelper('C1.salt.com','jack',123#将'C1.salt.com,jack,123'封装到self中的a1,a2,a3属性中
     

    上面的例子中,self是一个形式参数,当执行obj1 =  SQLHelper('C1.salt.com','alex',123)s时,self等于obj1;所以内容其实被封装到了对象obj1中,每个对象中的属性都会先存在内存里,类似下面这种方式保存:

        2、从某处调用被封装的内容

     调用被封装的内容时,有两种情况:1、通过对象直接调用;2、通过self间接调用。

     上图展示了对象obj1在内存中保存方式,根据保存格式可以如此调用被封装的内容:对象.属性名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Foo:
       
        def __init__(self, name, age):
            self.name = name
            self.age = age
       
        def detail(self):
            print self.name
            print self.age
       
    obj1 = Foo('haifeng', 18)
    obj1.detail()              # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 haifeng ;self.age 是 18
       
    ddj2 = Foo('jack', 73)
    obj2.detail()              # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 jack ; self.age 是 78

    从上面的例子可以看出,对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接取封装的内容。

        3、多层封装

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    class c1:
        def __init__(self,name,obj):
            self.name = name
            self.obj = obj           #这里的obj就是c2_obj
    class c2:
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def show(self):
            print(self.name)
            return 123
    class c3:
        def __init__(self,a1):
            self.money = 123
            self.aaa = a1
     
    c2_obj = c2('jack',18)
    c1_obj = c1('eric,c2_obj)       #将c2_obj当作参数传入c1_obj
    print(c1_obj.obj.age)            #这里打印的是age为18
     
    c3_obj = c3(c1_obj)
    print(c3_obj.aaa.obj.name)       #取到Jack这个用户名
    c3_obj.aaa.obj.show()         
     
    ret=c3_obj.aaa.obj.show()        #使用c3_obj执行show方法
    print(ret)                       #打印返回值
    jack
    None                             #打印结果时值为None,这是因为上面的函数没有定义返回值

    简单的解释一下上面的程序,就是一个多层封装的一个例子,首先定义了三个类,分别封装了不同的内容:

    •  c1_obj :封装了name='eric',obj = c2_obj

    • c2_obj :封装了name='jack',age=18

    • c3_obj :封装了 c1_obj这个对象

     ​当我们要想通过c1_obj来获取age属性的时候,就会先去找c1_obj的obj属性,obj属性有对应的是c2_obj对象,在c2_obj对象中找到age属性,获取方法就是:c1_obj.obj.age

     如果我们想通过c3_obj来执行show()方法的时候,首先我们看c3_obj有两个属性,money=123,aaa=c1_obj,没有show()方法,然后我们去找c1_obj对象。c1_obj对象中也没有show()方法,有obj=c2_obj,我们再去找c2_obj对象,c2_obj对象中有show()方法,执行show()方法:c3_obj.aaa.obj.show()

        (二)、继承特性

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class F1:                    #父类(基类)
        def show(self):
            print('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')
     
    obj = F2('jack')             
    obj.foo()                    #执行父类中的方法,这里F2会继承F1的foo方法打印jack

    那么问题来了,python是否可以继承多个类?如果可以继承了多个类每个类中都定了相同的函数,那么哪一个会被使用呢?

    带着这两个问题我们继续往下看,在python中类可以继承多个类,Java和C#中则只能继承一个类;如果python类继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先广度优先

     那么什么是深度优先和广度优选呢,下面同两张图和两个例子来分别介绍一下:

         1、深度优先,在类中由于可以定义多个类,在类()最左边的那个类优先继承

    在python2.*中:

            当类是经典类时,多继承情况下,会按照深度优先方式查找;

            当类时新式类时,多继承情况下,会按照广度优先方式查找。

    在python3中只有新式类,没有经典类了。

     那么什么是经典类,什么是新式类呢??

            顾名思义,一个老一个新,新的包含了更多的功能,也是之后推荐的写法,从写法上区分的话,如果当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。

    obj类是python内部定义的最顶层的基类,它是所有新式类的父类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #############################################
    class C1:       #C1是经典类
        pass
     
    class C2(C1):   #C2是经典类
        pass
     
    #############################################
    class N1(object):    #N1是新式类
        pass
     
    class N2(N1):        #N2是新式类
        pass
         
    #如果从子类的角度看,它的父类的父类的父类....其中任何一个继承了object,那么它就是新式类

    下面举个经典类的多继承的例子,方便大家理解:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    class F0:
     
        def bar(self):
            print 'F0.bar'
     
     
    class F1(F0):
     
        def bar(self):
            print 'F1.bar'
     
     
    class F2(F0):
     
        def bar(self):
            print 'F2.bar'
     
     
    class F3(F1, F2):
     
        def bar(self):
            print 'F3.bar'
     
    obj = F3()
    obj.bar()
     
    # 执行obj.bar方法时
    # 首先去F3类中查找,如果F3类中没有,则继续去F1类中找,如果F1类中么有,则继续去F0类中找,如果F0类中么有,则继续去F2类中找,如果还是未找到,则报错
    # 所以,查找顺序:F3 --> F1 --> F0 --> F2
    # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了

    在上面的例子中,如果父类中,有self就回到定义对象的位置重新查找,切记。

        2、广度优先

    下面举个新式类的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    class F0(object):
     
        def bar(self):
            print 'F0.bar'
     
     
    class F1(F0):
     
        def bar(self):
            print 'F1.bar'
     
     
    class F2(F0):
     
        def bar(self):
            print 'F2.bar'
     
     
    class F3(F1, F2):
     
        def bar(self):
            print 'F3.bar'
     
    obj = F3()
    obj.bar()
    # 执行bar方法时
    # 首先去F3类中查找,如果F3类中没有,则继续去F1类中找,如果F1类中么有,则继续去F2类中找,如果F2类中也没有,则继续去F0类中找,如果还是未找到,则报错
    # 所以,查找顺序:F3 --> F1 --> F2 --> F0

     ​

        (三)、多态特性

    静态语言 vs 动态语言

     1 class Animal(object):
     2     def run(self):
     3          print(Animal  is running...)
     4   
     5  class Dog(Animal):
     6     def run(self):
     7         print(Dog  is  running...)
     8  
     9 class Cat(Animal):
    10     def run(self):
    11         print(Cat is running...)
    12  
    13  
    14 obj = Dog()
    15 obj.run()
    定义动物类

    对于静态语言(例如:java、c#)来说:如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则将无法调用run()方法;

    对于python这样的动态语言来说: 则不一定需要传入Animal类型,我们只需要保证传入的对象有一个run()方法就可以了,如上例。

    这就是动态语言的"鸭子类型",它并不要求严格的继承体系,一个对象只要"看起来像鸭子,那它就可以被看做是鸭子"。

    今天主要介绍了什么是面向对象编程,创建类和方法以及类的三大特性,类还有很多高级的用法,会在以后介绍给大家,请持续关注。

     

     



  • 相关阅读:
    均值回归理论,均值回归法则是指万物最终都将回归于其长期的均值
    文本框仅允许输入大于0的正整数
    Angularjs接收服务端的布尔值
    Ajax POST单个对象或多个对象至API
    ASP.NET MVC程序重构
    查询数据库创建时间
    查询MS SQL的版本号
    获取Data和Log默认路径
    快速查找对象
    表关联使用INNER JOIN实现更新功能
  • 原文地址:https://www.cnblogs.com/phennry/p/5606718.html
Copyright © 2020-2023  润新知