新式类与经典类的比较

新式类与经典类的区别:

首先:

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 '''
new_style class
 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 '''
classic class

在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 '''
新式类的__slots__特性

 

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 '''
新式类__getattribute__()方法

可以看出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 '''
新式类构造函数指执行一次即可

 

posted @ 2017-04-16 19:57  ant_colonies  阅读(529)  评论(0编辑  收藏  举报