zoukankan      html  css  js  c++  java
  • Python基础篇【第7篇】: 面向对象(1)

    面向对象技术简介

    相近对象,归为类

      在人类认知中,会根据属性相近把东西归,并且给类别命名。比如说,鸟类的共同属性是有羽毛,通过产卵生育后代。任何一只特别的鸟都在鸟类的原型基础上的。面向对象就是模拟了以上人类认知过程。在Python语言,为了听起来酷,我们把上面说的“东西”称为对象(object)。

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

      类是一种数据结构,我们可以用它来定义对象,后者把数据值和行为特性融合在一起。类是现实世界的抽象的实体以编程形式出现。实例是这些对象的具体化。可以类比一下,类是蓝图或者模型,用来产生真实的物体(实例)。类还可以派生出相似但有差异的子类。编程中类的概念就应用了很多这样的特征。

      面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。

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

      下面是面向对象中的一些概念:

    • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
    • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
    • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
    • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
    • 实例变量:定义在方法中的变量,只作用于当前实例的类。
    • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
    • 实例化:创建一个类的实例,类的具体对象。
    • 方法:类中定义的函数。
    • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

    定义一个类

      在 Python 中,类声明与函数声明很相似,头一行用一个相应的关键字class,class之后为类的名称并以冒号结尾,接下来是一个作为它的定义的代码体,如下所示:

    class ClassName():
       '类文档字符串信息'   #类描述信息
       class_suite      #类结构体

      基类是一个或多个用于继承的父类的集合;class_suite 类体由所有声明语句,类成员定义,数据属性和函数组成。类通常在一个模块的顶层进行定义,以便类实例能够在类所定义的源代码文件中的任何地方被创建。类的帮助信息可以通过ClassName.__doc__查看。

    举例:创建一个员工类

    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    
    class Employee:
       '所有员工的基类'
       empCount = 0
    
       def __init__(self, name, salary):
          self.name = name
          self.salary = salary
          Employee.empCount += 1
       
       def displayCount(self):
         print "Total Employee %d" % Employee.empCount
    
       def displayEmployee(self):
          print "Name : ", self.name,  ", Salary: ", self.salary
    • empCount变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用Employee.empCount访问。
    • 第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法

    类属性

      属性就是属于对象的数据或者函数元素,可以通过我们熟悉的句点属性标识法来访问

    类的数据属性(静态变量)

      数据属性仅仅是所定义的类的变量。它们可以像任何其它变量一样在类创建后被使用,并且,要么是由类中的方法来更新,要么是在主程序其它什么地方被更新。 
      这种属性已为 OO 程序员所熟悉,即静态变量,或者是静态数据。它们表示这些数据是与它们所属的类对象绑定的,不依赖于任何类实例。

      静态成员通常仅用来跟踪与类相关的值。

    >>> class c(object):
          foo = 100
    >>> print c.foo
    100
    >>> c.foo+=1
    >>> c.foo
    101 

    二、由类实例化一个对象

    要创建一个类的实例,你可以使用类的名称,并通过__init__方法接受参数。

    "创建 Employee 类的第一个对象"
    emp1 = Employee("Zara", 2000)
    "创建 Employee 类的第二个对象"
    emp2 = Employee("Manni", 5000)

    三、访问属性

    您可以使用点(.)来访问对象的属性。使用如下类的名称访问类变量:

    emp1.displayEmployee()
    emp2.displayEmployee()
    print "Total Employee %d" % Employee.empCount

    举例:

    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    
    class Employee:
       '所有员工的基类'
       empCount = 0
    
       def __init__(self, name, salary):
          self.name = name
          self.salary = salary
          Employee.empCount += 1
       
       def displayCount(self):
         print "Total Employee %d" % Employee.empCount
    
       def displayEmployee(self):
          print "Name : ", self.name,  ", Salary: ", self.salary
    
    "创建 Employee 类的第一个对象"
    emp1 = Employee("Zara", 2000)
    "创建 Employee 类的第二个对象"
    emp2 = Employee("Manni", 5000)
    emp1.displayEmployee()
    emp2.displayEmployee()
    print "Total Employee %d" % Employee.empCount

    执行以上代码输出结果如下:

    Name :  Zara ,Salary:  2000
    Name :  Manni ,Salary:  5000
    Total Employee 2

    你可以添加,删除,修改类的属性,如下所示:

    emp1.age = 7  # 添加一个 'age' 属性
    emp1.age = 8  # 修改 'age' 属性
    del emp1.age  # 删除 'age' 属性

    你也可以使用以下函数的方式来访问属性:

    • getattr(obj, name[, default]) : 访问对象的属性。
    • hasattr(obj,name) : 检查是否存在一个属性。
    • setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
    • delattr(obj, name) : 删除属性。
      hasattr(emp1, 'age')    # 如果存在 'age' 属性返回 True。
      getattr(emp1, 'age')    # 返回 'age' 属性的值
      setattr(emp1, 'age', 8) # 添加属性 'age' 值为 8
      delattr(empl, 'age')    # 删除属性 'age'

    四、python内置属性类

    • __dict__ : 类的属性(包含一个字典,由类的数据属性组成)
    • __doc__ :类的文档字符串
    • __name__: 类名
    • __module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
    • __bases__ : 类的所有父类构成元素(包含了以个由所有父类组成的元组)

    Python内置类属性调用实例如下:

    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    
    class Employee:
       '所有员工的基类'
       empCount = 0
    
       def __init__(self, name, salary):
          self.name = name
          self.salary = salary
          Employee.empCount += 1
       
       def displayCount(self):
         print "Total Employee %d" % Employee.empCount
    
       def displayEmployee(self):
          print "Name : ", self.name,  ", Salary: ", self.salary
    
    print "Employee.__doc__:", Employee.__doc__
    print "Employee.__name__:", Employee.__name__
    print "Employee.__module__:", Employee.__module__
    print "Employee.__bases__:", Employee.__bases__
    print "Employee.__dict__:", Employee.__dict__

    执行以上代码输出结果如下:

    Employee.__doc__: 所有员工的基类
    Employee.__name__: Employee
    Employee.__module__: __main__
    Employee.__bases__: ()
    Employee.__dict__: {'__module__': '__main__', 'displayCount': <function displayCount at 0x10a939c80>, 'empCount': 0, 'displayEmployee': <function displayEmployee at 0x10a93caa0>, '__doc__': 'xe6x89x80xe6x9cx89xe5x91x98xe5xb7xa5xe7x9ax84xe5x9fxbaxe7xb1xbb', '__init__': <function __init__ at 0x10a939578>}

    下面正式介绍函数的三大特性:封装、继承、多态

    五、类的封装

      面向对象的程序设计中,某个类把所需要的数据(也可以说是类的属性)和对数据的操作(也可以说是类的行为)全部都封装在类中,分别称为类的成员变量和方法(或成员函数)。这种把成员变量和成员函数封装在一起的编程特性称为封装。

    六、类的继承

    面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。继承完全可以理解成类之间的类型和子类型关系。

    需要注意的地方:

    继承语法 

    class 派生类名(基类名)://... 基类名写作括号里,基本类是在类定义的时候,在元组之中指明的。

    在python中继承中的一些特点:

    • 1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。
    • 2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
    • 3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。

    如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。

    语法:

    派生类的声明,与他们的父类类似,继承的基类跟在类名之后,如下所示:

    class SubClassName (ParentClass1[, ParentClass2, ...]):      #如果多重(个)继承,不同父类用引号隔开即可
       'Optional class documentation string'
       class_suite
    # 子类也叫派生类,父类也叫作基类
    # Python的类可以继承多个类,Java和C#中则只能继承一个类

    实例:

    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    
    class Parent:        # 定义父类
       parentAttr = 100
       def __init__(self):
          print "调用父类构造函数"
    
       def parentMethod(self):
          print '调用父类方法'
    
       def setAttr(self, attr):
          Parent.parentAttr = attr
    
       def getAttr(self):
          print "父类属性 :", Parent.parentAttr
    
    class Child(Parent): # 定义子类
       def __init__(self):
          print "调用子类构造方法"
    
       def childMethod(self):
          print '调用子类方法 child method'
    
    c = Child()          # 实例化子类
    c.childMethod()      # 调用子类的方法
    c.parentMethod()     # 调用父类方法
    c.setAttr(200)       # 再次调用父类的方法
    c.getAttr()          # 再次调用父类的方法

    以上代码执行结果如下:

    调用子类构造方法
    调用子类方法 child method
    调用父类方法
    父类属性 : 200

    你可以继承多个类

    class A:        # 定义类 A
    .....
    
    class B:         # 定义类 B
    .....
    
    class C(A, B):   # 继承类 A 和 B
    .....

    扩展1:新式类和经典类

    新式类的由来:随着Python版本的发展,python2.2版本以后引入的关于类的新概念,官方解释:为了统一类(class)和类型(type)。与之相对应的就是经典类。

    在2.2之前,比如2.1版本中,类和类型是不同的,如a是ClassA的一个实例,那么a.__class__返回 ‘ class    __main__.ClassA‘ ,type(a)返回总是<type 'instance'>。而引入新类后,比如ClassB是个新类,b是ClassB的实例,b.__class__和type(b)都是返回‘class '__main__.ClassB' ,这样就统一了。

    引入新类后,还有其他的好处,比如更多的内置属性将会引入,描述符的引入,属性可以来计算等等。

    为了向前兼容,默认情况下用户定义的类为经典类,新类需要继承自所有类的基类 object 或者继承自object的新类。【即只要是能向上追溯到继承自object类,就叫做新式类】

        

    class CC:             #经典类
        def __init__( self ):
            pass
     
    class CCN(object):    #新类
        def __init__( self ):
            pass 
     
    c1 = CC()
    c2 = CCN()
     
    c1.__class__            # 输出-> <class __main__.CC at 0x0137BF10>
    type(c1)                # 输出-> <type 'instance'>
     
    c2.__class__            # 输出-><class '__main__.CCN'>
    type(c2)                # 输出-><class '__main__.CCN'>
     
    dir(c1)

    新式类对多重继承的影响:在多重继承中,如果不同父类中拥有相同的方法,在进行方法解析时采用的顺序(mro即method resolution order)是:

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

    class D:
    
        def bar(self):
            print 'D.bar'
    
    class C(D):
    
        def bar(self):
            print 'C.bar'
    
    class B(D):
    
        def bar(self):
            print 'B.bar'
    
    class A(B, C):
    
        def bar(self):
            print 'A.bar'
    
    a = A()
    # 执行bar方法时
    # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
    # 所以,查找顺序:A --> B --> D --> C
    # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
    a.bar()
    class D(object):
    
        def bar(self):
            print 'D.bar'
    
    
    class C(D):
    
        def bar(self):
            print 'C.bar'
    
    
    class B(D):
    
        def bar(self):
            print 'B.bar'
    
    
    class A(B, C):
    
        def bar(self):
            print 'A.bar'
    
    a = A()
    # 执行bar方法时
    # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
    # 所以,查找顺序:A --> B --> C --> D
    # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
    a.bar()

    经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错

    新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错

    注意:在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了

    六、方法重写

     Pyhon不支持多态并且也用不到多态,多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。

    如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法(就是子类中重新定义一个需要重写的在父类中的方法):

    实例:

    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    
    class Parent:        # 定义父类
       def myMethod(self):
          print '调用父类方法'
    
    class Child(Parent): # 定义子类
       def myMethod(self):
          print '调用子类方法'
    
    c = Child()          # 子类实例
    c.myMethod()         # 子类调用重写方法

    执行以上代码输出结果如下:

    调用子类方法        #这个结果是子类重写后的结果

    到此,Python类的基本概念:封装、继承、多态就可理解为这么多,下一篇我们来继续深究Python面向对象编程。

  • 相关阅读:
    图片滤镜高斯模糊
    context.Request.Files为NULL问题 在实现图片上传功能的时候出现在ashx等处理页面出现context.Request.Files为NULL异常,有几点需要注意:
    C#中使用代码动态改变配置文件信息
    缓存
    使用iframe实现图片上传预览效果
    loading 加载
    sql 查询每月的销售金额
    GridView数据格式化
    把图片转换成二进制--把二进制转换成图片
    asp.net js 倒计时总秒数量 和 排序
  • 原文地址:https://www.cnblogs.com/sunailong/p/5021186.html
Copyright © 2011-2022 走看看