美文网首页
Python学习笔记6

Python学习笔记6

作者: MetaT1an | 来源:发表于2018-09-02 11:06 被阅读0次

    面向对象(补充)上一部分

    • 描述器
    • 生命周期
    • 内存管理
    • 面向对象三大特性
    • 类的设计原则

    描述器

    • 描述器是一个对象,用来描述其他对象属性的操作;作用是对属性的操作做验证和过滤。
    • 前面只读属性案例中就是用到了描述器。
    • 在对象的内部增加一个描述器,可以接管对象属性的增删改查操作。
    class Age:
        def __get__(self, instance, owner):     # instance是拥有 age属性的对象
            pass
        
        def __set__(self, instance, value):
            instance.v = value      # 将变量的值绑定在 Person的实例中
        
        def __delete__(self, instance):
            pass
        
    class Person:
        age = Age()
        
    
    # age实例是 p1和 p2两个对象所共享的,所以 Age对象及实例不应该具有属性,只单纯地提供方法即可
    p1 = Person()
    p1.age = 19      # 调用 __set__()
    print(p1.age)    # 调用 __get__()
    
    p2 = Person()
    p2.age = 20
    print(p2.age)   # 20
    
    • 资料描述器非资料描述器
      • 资料描述器:实现了__get__()__set__()
      • 非资料描述器:仅仅实现了__get__()
    • 实例属性和描述器重名时,操作的优先级如下:
      • 资料描述器 > 实例属性 > 非资料描述器

    生命周期

    • 表示一个对象从创建到释放的过程
    class Person:
        __count = 0
        
        def __init__(self):
            Person.__count += 1
            
        def __del__(self):
            Person.__count -= 1
            
        @classmethod
        def log(cls):
            print("we have %d people" % cls.__count)
            
    p1 = Person()
    Person.log()    # we have 1 people
    p2 = Person() 
    Person.log()    # we have 2 people
    

    内存管理机制

    • 万物皆对象,不存在基本数据类型
    • 对于相等的整数 [-5, 正无穷) 和短小的字符串,Python会进行缓存,不会创建多个对象
    n1 = 1
    n2 = 1
    print(id(n1), id(n2))   # 1708655056 1708655056
    
    • 容器对象:存储的对象,仅仅是其他对象的引用(列表)
    • 内存回收
      • 引用计数
        • 一个对象会记录着自身被引用的个数
        • 每增加一个引用,引用数+1,减少一个引用,引用数-1
        • 引用数为0的时候,会被当做垃圾进行回收
        • 会出现连个对象循环引用的问题
      • 垃圾回收
        • 从经历过引用计数机制但仍然未被释放的对象中,进行内存释放
        • 新增的对象个数 - 消亡对象的个数达到一定阈值时才进行垃圾检测
      • 分代回收
        • 分代回收是垃圾回收的高效解决方案,不需频繁地进行垃圾检测
        • 存活时间越久的对象,越不可能在后面的过程中变成垃圾
        • 设立0, 1, 2三代对象集合,对其中的对象进行不同频率的检测
        • 第一次检测存活下来的,从0代纳入1代,0代检测一定次数后开始检测1代,以此类推
    • 深拷贝和浅拷贝
      • 浅拷贝
      a = [1, 2, 3]
      b = a
      print(id(a), id(b))   # 2229855665608 2229855665608
      
      • 深拷贝
      import copy
      
      a = [1, 2, 3]
      c = copy.deepcopy(a)
      print(id(a), id(c))   # 2229855665608 2229861709896
      
      • copydeepcopy的区别
      import copy
      
      a = [1, 2, 3]
      b = [4, 5, 6]
      c = [a, b]
      d = copy.deepcopy(c)
      e = copy.copy(c)
      
      image
      • 使用copy拷贝可变类型时,进行单层次的深拷贝,若拷贝的是不可变类型,则进行浅拷贝。

    面向对象三大特性

    • 封装继承多态
    继承
    • 非私有的属性和方法可以被继承,继承不是拷贝了资源,而是具有了资源的访问权,资源的存储位置在父类中,实现资源重用
    • Python中可以使用多继承
    # 所有的类都继承了 object类
    # 所有的类对象都由 type实例化出来
    class A:
        pass
        
    class B:
        pass
        
    class C(A, B):      # C 类继承了 A和 B类
        pass
        
    print(C.__bases__)      # (<class '__main__.A'>, <class '__main__.B>)
    print(int.__base__)     # (<class 'object'>)
    print(bool.__base__)    # (<class 'int'>)
    
    • 几种继承的形式


      image
    • 资源查找顺序

      • 单继承链:C-->B-->A
      • 无重叠多继承链:按照单继承链深度优先查找(C-->B-->A-->D-->E)
      • 有重叠多继承链:广度优先查找(C-->B-->D-->A)
    • 资源覆盖

      • 在优先级较高的类中重新定义了同名的属性和方法,再次调用时,会调用到优先级较高类中的资源,并不是相关的资源在内存上被覆盖了,而是调用优先级出现了变化
    • selfcls

    # 谁调用方法,self 和 cls 就是谁
    # 带着参数去找方法
    
    class A:
        def show(self):
            print(self)
            
        @classmethod
        def tell(cls):
            print(cls)
            
    class B(A):
        pass
    
    B.tell()        # <class '__main__.B'>
    B().show()      # <__main__.B object at 0x027674D0>
    
    • 资源的累加
    class A:
        def __init__(self):
            self.x = 2
    
    class B(A):
        pass
    
    class C(A):
        def __init__(self):
            self.y = 1
    
    class D(A):
        def __init__(self):
            self.y = 1
            
    class E(A):
        def __init__(self):
            super().__init__()      # 会调用 A的构造函数,参数可以省略
            # A.__init__(self)       //和上面等价,要传参
            self.y = 1
            
    b = B()
    print(b.x)      # 2, 调用了父类的构造函数,b 调用,x就是 b的
    
    c = C()
    print(c.y)      # 1, C有了构造函数,就调用 C的,A的构造函数不会被调用
    print(c.x)      # 报错,没有这个属性
    
    e = E()
    print(e.x, e.y)     # 2, 1 
    
    多态
    • Python是动态类型的语言,不需要严格意义上的多态
    def test(obj):
        obj.func()
        
    # 只要传入的参数有 func()这个方法,就可以传入进行执行,不用进行类型检测。
    # 不需要按照其他静态语言那样沿着继承链进行方法调用形成多态
    

    类的设计原则

    • 单一职责原则:一个雷只负责一项职责
    • 开放封闭原则:对外扩展开放,对内修改关闭
    • 里式替换原则:子类所继承下来的属性和方法都需能够合理地使用
    • 接口分离原则:功能一致的方法应该重新组成新的接口/类,进行细分
    • 依赖倒置原则:高层模块不应该直接依赖低层模块,核心是面向接口编程

    相关文章

      网友评论

          本文标题:Python学习笔记6

          本文链接:https://www.haomeiwen.com/subject/dnzpwftx.html