zoukankan      html  css  js  c++  java
  • 面向对象_新式类与经典类

      在python2中,没有显式继承object的类以及该类的子类,都是经典类。显示的声明继承object的类以及该类的子类都是新式类。在python3中,无论是否继承object,都默认继承object,即python3中的所有类均为新式类

      __new__

      新式类新增了__new__方法,它的原型是object.__new__(cls,[,.....])。cls是一个类对象,当你调用C(*args,**kwargs)来创建一个类C的实例时,python内部调用的是C.__new__(C,*args,**kwargs),然后返回是类C的实例c,在确认c是C的实例后,python再调用C.__init__(C,*args,**kwargs)来初始化实例c。

    class Person():
    
        def __new__(cls, name,age):
            print('__new__ called')
            return super(Person,cls).__new__(cls)
    
        def __init__(self,name,age):
            print('__init__ called')
            self.name = name
            self.age = age
    
        def __str__(self):
            return ('123')
    
    p1 = Person('lary',18)
    print(p1)

      __slots__

      新式类具有__slots__属性,该属性会对生成子类实例产生影响。当类C中有比较少的变量,而且拥有__slots__属性时,类C的实例就没有__dict__属性,而是把变量值存在一个固定的地方。__slots__属性虽然令实例失去了绑定任意属性的遍历,但是因为每一个实例没有__dict__属性,却能有效减少每一个实例消耗的内存,有利于生成小而精干的实例。

      __getattirbute__

      对新式类的实例来说,所有属性和方法的访问都是通过__getattribute完成。这是由object基类实现的。

    class animal(object):
    
        def __getattribute__(self, item):
           return object.__getattribute__(self,item)()
    
        def eat(self):
            print('eating...')
    
    #print(animal.__dict__)
    cat = animal()
    #print(cat.__dict__)
    cat.eat
    # #当获取属性时,直接return object.__getattribute__(self,*args,**kwargs)
    # #如果需要获取某个方法的返回值时,则需要在函数后面加上一个()即可,如果不加的话,返回的是函数引用地址
    # #在__getattribute__方法里面,不能用self.xxx这种方式调用。因为调用类的属性每次都会强制调用__getattribute__,所以会导致递归调用

      实例方法的调用

      在经典对象模型中,无论是显式调用还是隐式调用特殊方法,都会调用实例中后绑定的特殊方法。而在新的对象模型中,除非显式的调用实例的特殊方法,否则python总是会去调用类中定义的特殊方法,如果没有定义的话就报错。

    def getItem(index):
        return index + 1
    
    class C():
        pass
    
    c = C()
    c.__getitem__ = getItem
    print(c[1])             #隐式访问报错
    
    print(c.__getitem__(1)) #显示访问成功

      多继承

      新式类同样支持多继承,但是如果新式类想要从多个内置类型中生成一个新类的话,则这些内置类必须是经过精心设计,能够互相兼容的。

      mro

      在经典对象模型中,方法和属性的查找链遵循深度优先。而在新式类中,对象模型方法和属性的查找遵循广度优先。

      super方法

      当你使用super()函数时,python会在mro列表上继续搜索下一个类,只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个mro列表,每个地方也只会被调用一次。

    class Base:
        def __init__(self):
            print('Base.__init__')
    
    class A(Base):
        def __init__(self):
            super().__init__()
            print('A.__init__')
    
    class B(Base):
        def __init__(self):
            super().__init__()
            print('B.__init__')
    
    class C(A,B):
        def __init__(self):
            super().__init__()  # Only one call to super() here
            print('C.__init__')
    
    c = C()

      属性装饰器

      经典类具有一种@property装饰器,而新式类具有三种属性装饰器

       @property
        def price(self):
            print ('@property')
    
        @price.setter
        def price(self, value):
            print ('@price.setter')
    
        @price.deleter
        def price(self):
            print ('@price.deleter')
    
    obj = C()
    obj.price          # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
    obj.price = 123    # 自动执行 @price.setter 修饰的 price 方法,并将  123 赋值给方法的参数
    del obj.price      # 自动执行 @price.deleter 修饰的 price 方法
  • 相关阅读:
    Linux下修改HOSTNAME
    IBM服务器 IMM日志收集
    X3850 Linux 下DSA日志收集办法
    Linux查看进程内存占用及内存使用情况
    集成开发注意事项(持续更新)
    SOAPUI请求及mockservice 使用
    Linux下su与su -命令的区别
    从XML文件中获取格式化的文本信息
    前端实现下载文件
    动态表单如何对部分表单字段校验
  • 原文地址:https://www.cnblogs.com/iamluoli/p/9968435.html
Copyright © 2011-2022 走看看