zoukankan      html  css  js  c++  java
  • python

    写了这么多python 代码,也常用的类和对象,这里准备系统的对python的面向对象编程做以下介绍。

    面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)

    面向对象:对函数进行分类和封装,让开发“更快更好更强...”

    创建类和对象

    面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。

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

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

    创建一个类

    class EmployeeInfo():
        '创建一个员工信息类'   # 类文档字符串 位置在类名下单引号中, 类的帮助信息可以通过ClassName.__doc__查看。
    
        #class_suite   类体  由类成员,方法,数据属性组成。
    
    print EmployeeInfo.__doc__   # 创建一个员工信息类

    应用实例

    # 创建一个类,应用实例
    
    class EmployeeInfo():
        '员工信息类'
    
        # 定义员工数量,初始化为0 ,每实例化一个对象时,数量增 1
        empCount = 0
    
        def __init__(self,name,age):  # 类中的函数第一个参数必须是self(详细见:类的三大特性之封装)类中定义的函数叫做 “方法”
    
            self.name = name
            self.age = age
            EmployeeInfo.empCount += 1
    
        def displayEmployeeInfo(self):
    
            print "员工姓名:",self.name,"员工年龄:",self.age,"员工序号:",self.empCount
    
    
    emp1 = EmployeeInfo("Tester",18)
    
    emp1.displayEmployeeInfo()  # 输出结果 员工姓名: Tester 员工年龄: 18 员工序号: 1
    
    emp2 = EmployeeInfo("Manager",19) 
    
    emp2.displayEmployeeInfo()  # 员工姓名: Manager 员工年龄: 19 员工序号: 2
    • empCount 变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 Employee.empCount 访问。
    • 第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法(可以不写,根据实际需要自己定义需要的构造函数)。

    • self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。

    注意:self 代表的是一个实例,如果使用self.变量,标识的是实例化的变量,如果要使用类变量,必须使用,类名.变量。如:EmployeeInfo.empCount += 1。

    self代表类的实例,而非类

    类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。

    # 创建一个测试类
    
    class Test:
        '创建一个测试类'
        def prt(self):
            print(self)
            print(self.__class__)
    t = Test()
    t.prt()

    以上实例执行结果为:

    <__main__.Test instance at 0x00000000026CB088>
    __main__.Test

    从执行结果可以很明显的看出,self 代表的是类的实例,代表当前实例对象的地址,而self.__class__ 则指向该类。

    类的属性

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

    • getattr(obj, name[, default]) : 访问对象的属性。
    • hasattr(obj,name) : 检查是否存在一个属性。
    • setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
    • delattr(obj, name) : 删除属性。

    应用举例

    # 如果存在 'age' 属性返回 True。
    print hasattr(emp1,'age') # True
    # 返回 'age' 属性的值
    print getattr(emp1,'age') # 18
    # 添加属性 'num' 值为 1
    print setattr(emp1,'num',1) # None
    # 返回 'num' 属性的值
    print getattr(emp1,'num') # 1
    # 删除属性 'age'
    print delattr(emp1,'num') # None
    
    print getattr(emp1,'num') # 返回为空

    Python内置类属性

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

    执行结果

    EmployeeInfo.__doc__: 员工信息类
    EmployeeInfo.__name__: EmployeeInfo
    EmployeeInfo.__module__: __main__
    EmployeeInfo.__bases__: ()
    EmployeeInfo.__dict__: {'__module__': '__main__', 'empCount': 2, '__doc__': 'xe5x91x98xe5xb7xa5xe4xbfxa1xe6x81xafxe7xb1xbb', '__init__': <function __init__ at 0x00000000026F2E48>, 'displayEmployeeInfo': <function displayEmployeeInfo at 0x00000000026F2EB8>}

    python 析构函数 

    析构函数 __del__ ,__del__在对象销毁的时候被调用当对象不再被使用时,__del__方法运行:

    class Point:
       def __init__( self, x=0, y=0):
          self.x = x
          self.y = y
       def __del__(self):
          class_name = self.__class__.__name__
          print class_name, "销毁"
     
    pt1 = Point()
    pt2 = pt1
    pt3 = pt1
    print id(pt1), id(pt2), id(pt3) # 打印对象的id
    del pt1
    del pt2
    del pt3

    以上实例运行结果如下:

    3083401324 3083401324 3083401324
    Point 销毁

    注意:通常你需要在单独的文件中定义一个类,当然python中一个文件也可以定义多个类,不推荐。

    类的继承

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

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

    需要注意的地方:继承语法 class 派生类名(基类名)://... 基类名写在括号里,基本类是在类定义的时候,在元组之中指明的。

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

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

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

    语法:

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

    class SubClassName (ParentClass1[, ParentClass2, ...]):
       'Optional class documentation string'
       class_suite

    示例

    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 '调用子类方法'
     
    c = Child()          # 实例化子类
    c.childMethod()      # 调用子类的方法
    c.parentMethod()     # 调用父类方法
    c.setAttr(200)       # 再次调用父类的方法 - 设置属性值
    c.getAttr()          # 再次调用父类的方法 - 获取属性值

    以上代码执行结果如下:

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

    你可以继承多个类

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

    那么问题又来了,多继承呢?

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

    1、Python的类可以继承多个类,Java和C#中则只能继承一个类

    2、Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先广度优先

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

    经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果 当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。

     

    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类中找,如果还是未找到,则报错

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

    你可以使用issubclass()或者isinstance()方法来检测。

    • issubclass() - 布尔函数判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)
    • isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。

    示例

    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 '调用子类方法'
    
    p = Parent
    
    c = Child()          # 实例化子类
    c.childMethod()      # 调用子类的方法
    c.parentMethod()     # 调用父类方法
    c.setAttr(200)       # 再次调用父类的方法 - 设置属性值
    c.getAttr()          # 再次调用父类的方法 - 获取属性值
    
    print issubclass(Child,Parent) #  True  issubclass() - 布尔函数判断第一个类是第二个类的子类或者子孙类,语法:issubclass(子类名,父类名)
    
    print isinstance(c,Parent) # True  isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。

    方法重写

     如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法:

     示例

    class Parent:        # 定义父类
       def myMethod(self):
          print '调用父类方法'
     
    class Child(Parent): # 定义子类
       def myMethod(self):
          print '调用子类方法'
     
    c = Child()          # 子类实例
    c.myMethod()         # 子类调用重写方法

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

    调用子类方法

     多态 

     多态(Polymorphism):意味着可以对不同类的对象使用同样的操作,他们会像被“施了魔法一般”工作。

    class F1:
        pass
    
    
    class S1(F1):
    
        def show(self):
            print 'S1.show'
    
    
    class S2(F1):
    
        def show(self):
            print 'S2.show'
    
    def Func(obj):
        print obj.show()
    
    s1_obj = S1()
    Func(s1_obj)   # 'S1.show'
    s2_obj = S2() 
    Func(s2_obj)
    # 'S2.show'
    Python “鸭子类型”

    class A:    
        def prt(self):    
            print "A"    
        
    class B(A):    
        def prt(self):    
            print "B"    
                
    class C(A):    
        def prt(self):    
            print "C"    
               
    class D(A):    
        pass    
        
    class E:    
        def prt(self):    
            print "E"    
        
    class F:    
        pass    
        
    def test(arg):    
        arg.prt()    
        
    a = A()    
    b = B()    
    c = C()    
    d = D()    
    e = E()    
    f = F()    
        
    test(a)    
    test(b)    
    test(c)    
    test(d)    
    test(e)    
    test(f)    

    输出结果: 

    A  
    B  
    C  
    A  
    E  
    Traceback (most recent call last):  
      File "/Users/shikefu678/Documents/Aptana Studio 3 Workspace/demo/demo.py", line 33, in <module>  
        test(a),test(b),test(c),test(d),test(e),test(f)  
      File "/Users/shikefu678/Documents/Aptana Studio 3 Workspace/demo/demo.py", line 24, in test  
        arg.prt()  
    AttributeError: F instance has no attribute 'prt'  

    a,b,c,d都是A类型的变量,所以可以得到预期的效果(从java角度的预期),e并不是A类型的变量但是根据鸭子类型,走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子,e有prt方法,所以在test方法中e就是一个A类型的变量,f没有prt方法,所以f不是A类型的变量。

  • 相关阅读:
    android开发环境搭建日记和嵌入式Android开发环境初探
    QT210 android2.3 和android4.0 烧写编译日记
    RAM,SRAM,DRAM,SDRAM,DDR RAM,ROM,PROM,EPROM,EEPROM,NAND FLASH,NOR FLASH的区别
    如何修改终端用户名颜色修改为红色(可以自由定制)
    FPGA机器学习之stanford机器学习第三堂2
    FPGA机器学习之stanford机器学习第三堂1
    FPGA机器学习之stanford机器学习第二堂2
    FPGA机器学习之stanford机器学习第二堂1
    FPGA机器学习之stanford机器学习第一堂
    FPGA片外存储器ddr2之DQSn引脚的分析
  • 原文地址:https://www.cnblogs.com/BlueSkyyj/p/7693649.html
Copyright © 2011-2022 走看看