• python-面向对象编程


    转载:https://www.cnblogs.com/BlueSkyyj/p/7693649.html

    面向对象编程

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

    创建类和对象

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

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

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

    创建一个类

    class EmpolyeeInfo():

        '员工信息类'

        #定义员工数量、初始化为0,每实例化一个对象时,数量增1

        empCount=0

        def __init__(self,name,age):   #类中的函数第一个参数必须是self,类中定义的函数叫做“方法”

            self.name=name

            self,age=age

            EmpolyeeInfo.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.displayEmployInfo()   #员工姓名:manager 员工年龄:19 员工序号:2

    1、empCount变量是一个类变量,它的值将在这个类的所有实例之间共享,你可以在内部类或外部类使用Employee.empCount访问

    2、第一种方法__init__()方法是一种特殊的方法,被成为类的构造方法或初始化方法,当创建了这个类的实例时久会调用该方法(可以不写,根据实际需要自己定义需要的构造方法)。

    3、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类型的变量。

    
    
  • 相关阅读:
    项目
    关于我
    【转载】罗胖精选|什么样的自控方法才有效?
    知识管理——得到CEO脱不花女士的一次分享
    注意由双大括号匿名类引起的serialVersionUID编译告警
    持续集成、持续交付和持续部署
    Google Cayley图数据库使用方法
    任务的属性
    团队博客地址
    个人总结
  • 原文地址:https://www.cnblogs.com/yuany66/p/12102572.html
Copyright © 2020-2023  润新知