面向对象_新式类与经典类
在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 方法