新式类与经典类的比较
新式类与经典类的区别:
Python 2.x中默认都是经典类,只有显式继承了object才是新式类
Python 3.x中默认都是新式类,不必显式的继承object
即:新式类都从object继承,经典类不需要
其次:------新式类对象可以直接通过__class__属性获取自身类型:type
------继承搜索的顺序发生了改变
经典类多继承属性搜索顺序: 先深入继承树左侧,再返回,开始找右侧 —— 即 经典类深度优先
新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动 —— 即 新式类广度优先
------新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中
------新式类增加了__getattribute__方法
------新式类相同父类只执行一次构造函数,经典类重复执行多次。
1、新式类对象可以直接通过__class__属性获取自身类型(type)
1 #-*- coding:utf-8 -*- 2 # 3 class E1(object): 4 pass 5 6 print('new_style class') 7 e1 = E1() 8 print(e1) 9 print(e1.__class__) 10 print(type(e1)) 11 12 ''' 13 new_style class 14 <__main__.E1 object at 0x7f76acfc2320> 15 <class '__main__.E1'> 16 <class '__main__.E1'> 17 18 '''
1 # -*- coding:utf-8 -*- 2 # 3 4 class E: 5 pass 6 7 e = E() 8 print('classic class') 9 print(e) 10 print(type(e)) 11 print(e.__class__) 12 13 ''' 14 classic class 15 <__main__.E instance at 0x7f31b429afc8> 16 <type 'instance'> 17 __main__.E 18 19 '''
在Python2.7下运行,E1是定义的新式类。那么输出e1的时候,不论是type(e1),还是e1.__class__都是输出的<class '__main__.E1'>。
2、经典类深度优先,新式类广度优先
1 #-*- coding:utf-8 -*- 2 # 3 4 class A(object): 5 ''' 6 新式类,作为所有类的基类 7 ''' 8 def foo(self): 9 print('class A') 10 11 class A1: 12 ''' 13 经典类,作为所有类的基类 14 ''' 15 def foo(self): 16 print('class A1') 17 18 class C(A): 19 pass 20 21 class C1(A1): 22 pass 23 24 class D(A): 25 def foo(self): 26 print('class D') 27 28 class D1(A1): 29 def foo(self): 30 print('class D1') 31 32 class E(C, D): 33 pass 34 35 class E1(C1, D1): 36 pass 37 38 39 e = E() 40 e.foo() 41 e1 = E1() 42 e1.foo() 43 44 ''' 45 class D 46 class A1 47 '''
因为A新式类,对于继承A类都是新式类,首先要查找类E中是否有foo(),如果没有则按顺序查找C->D->A。它是一种广度优先查找方式。
因为A1经典类,对于继承A1类都是经典类,首先要查找类E1中是否有foo(),如果没有则按顺序查找C1->A1->D1。它是一种深度优先查找方式。
3、新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author: antcolonies 4 5 class A(object): 6 __slots__ = ('name', 'age') 7 8 class A1: 9 __slots__ = ('name', 'age') 10 11 12 a = A() 13 a1 = A1() 14 15 a.name1 = 'a' 16 a1.name1 = 'a1' 17 18 ''' 19 Traceback (most recent call last): 20 File "E:/python14_workspace/s14/day06/py_1.py", line 15, in <module> 21 a.name1 = 'a' 22 AttributeError: 'A' object has no attribute 'name1' 23 '''
A是新式类添加了__slots__ 属性,所以只允许添加 ‘name’ 和 ‘age’ 两种属性
A1经典类__slots__ 属性不起作用。
通常每一个实例都会有一个__dict__属性,用来记录实例中所有的属性和方法,也是通过这个字典,可以让实例绑定任意的属性;
而__slots__属性作用就是,当一个类C有比较少的变量,而且拥有__slots__属性时,类C的实例就没有__dict__属性,而是把变量的值存在一个固定的地方。如果试图访问一个__slots__中没有的属性,实例就会报错。这样操作有什么好处呢?__slots__属性虽然令实例失去了绑定任意属性的便利,但是因为每一个实例没有__dict__属性,却能有效节省每一个实例的内存消耗,有利于生成小而精干的实例。
1 #-*- coding:utf-8 -*- 2 # 3 4 class A(object): 5 __slots__ = ('name', 'age') 6 7 class A1: 8 __slots__ = ('name', 'age') 9 10 11 a = A() 12 a1 = A1() 13 14 # a.name1 = 'a' 15 a1.name1 = 'a1' 16 a1.name = 'Tom' 17 a1.age = '23' 18 a.name = 'Tim' 19 a.age = '22' 20 print(a1.__dict__) 21 print(a.__slots__) 22 print(a.name, a.age) 23 print(a.__dict__) 24 25 ''' 26 {'age': '23', 'name': 'Tom', 'name1': 'a1'} 27 ('name', 'age') 28 ('Tim', '22') 29 Traceback (most recent call last): 30 File "py_4.py", line 21, in <module> 31 print(a.__dict__) 32 AttributeError: 'A' object has no attribute '__dict__' 33 '''
4、新式类增加了__getattribute__方法
1 #-*- coding:utf-8 -*- 2 # 3 4 class A(object): 5 def __getattribute__(self, *args, **kwargs): 6 print('A.__getattribute__') 7 8 class A1: 9 def __getattribute__(self, *args, **kwargs): 10 print('A1.__getattribute__') 11 12 13 a = A() 14 a1 = A1() 15 16 a.test 17 print('============') 18 a1.test 19 20 ''' 21 A.__getattribute__ 22 ============ 23 Traceback (most recent call last): 24 File "py_5.py", line 18, in <module> 25 a1.test 26 AttributeError: A1 instance has no attribute 'test' 27 '''
可以看出A是新式类,每次通过实例访问属性,都会经过__getattribute__函数,A1不会调用__getattribute__所以出错了。
5、新式类相同父类只执行一次构造函数,经典类重复执行多次。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author: antcolonies 4 5 class A: 6 def __init__(self): 7 print('a', end='') 8 9 class B(A): 10 def __init__(self): 11 A().__init__() 12 print('b', end='') 13 14 class C(A): 15 def __init__(self): 16 A().__init__() 17 print('c', end='') 18 19 class D(B, C): 20 def __init__(self): 21 B().__init__() 22 C().__init__() 23 print('d', end='') 24 25 class E(D, A): 26 def __init__(self): 27 D().__init__() 28 A().__init__() 29 print('e', end='') 30 31 d = D() 32 print('') 33 e = E() 34 35 ''' 36 aabaabaacaacd 37 aabaabaacaacdaabaabaacaacdaae 38 '''
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author: antcolonies 4 5 class A(object): 6 def __init__(self): 7 print('a', end='') 8 9 class B(A): 10 def __init__(self): 11 super(B,self).__init__() 12 print('b', end='') 13 14 class C(A): 15 def __init__(self): 16 super(C, self).__init__() 17 print('c', end='') 18 19 class D(B, C): 20 def __init__(self): 21 super(D, self).__init__() 22 print('d', end='') 23 24 class E(D, A): 25 def __init__(self): 26 super(E, self).__init__() 27 print('e', end='') 28 29 d = D() 30 print('') 31 e = E() 32 33 ''' 34 acbd 35 acbde 36 '''