新式类和经典类的区别
前言:
- 从Python2.2开始,Python 引入了 new style class(新式类)
- Python 2.x中默认都是经典类,只有显式继承了object才是新式类
- Python 3.x中默认都是新式类,不必显式的继承object
1、新式类对象可以直接通过__class__
属性获取自身类型:type
# coding:utf8
class A:
# 经典类
pass
class A1(object):
# 新式类
pass
a = A()
print "经典类"
print a
print type(a)
print a.__class__
print "新式类"
a1 = A1()
print a1
print type(a1)
print a1.__class__
输出:
经典类
<__main__.A instance at 0x1038ba368>
<type 'instance'>
__main__.A
新式类
<__main__.A1 object at 0x102d49e90>
<class '__main__.A1'>
<class '__main__.A1'>
E1是定义的新式类,那么输输出a1的时候,不论是type(a1)
,还是a1.__class__
都是输出的<class '__main__.A1'>
,保持了class与type的统一;
2、对于多重继承的属性搜索顺序不一样
新式类是采用C3 MRO的算法处理多继承的(简单理解为 广度优先搜索,但不完全是),旧式类采用深度优先搜索
class A():
def __init__(self):
pass
def save(self):
print "This is from A"
class B(A):
def __init__(self):
pass
class C(A):
def __init__(self):
pass
def save(self):
print "This is from C"
class D(B,C):
def __init__(self):
pass
fun = D()
fun.save()
经典类的答案: This is from A
新式类的答案: This is from C
3、新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中
# -*- coding:utf-8 -*-
class A():
__slots__ = ('name', 'age')
class A1(object):
__slots__ = ('name', 'age')
a = A()
a1 = A1()
a.name = "a_name"
print a.name
a.name1 = "a_name1"
print a.name1
# a.name1 = "a"
a1.name = "a1_name"
print a1.name
a1.name1 = "a1_name1"
print a1.name1
输出:
a_name
a_name1
a1_name
File "xxx/new_old_class.py", line 21, in <module>
a1.name1 = "a1_name1"
AttributeError: 'A1' object has no attribute 'name1'
A1是新式类添加了__slots__ 属性,所以只允许添加name age
,所以a1.name1是会出错的;
A经典类__slots__ 属性没用,所以a.name1没有问题。
通常每一个实例都会有一个__dict__属性,用来记录实例中所有的属性和方法,也是通过这个字典,可以让实例绑定任意的属性;
而__slots__属性作用就是,当类C有比较少的变量,而且拥有__slots__属性时,类C的实例 就没有__dict__属性,而是把变量的值存在一个固定的地方。如果试图访问一个__slots__中没有的属性,实例就会报错。
这样操作有什么好处呢?__slots__属性虽然令实例失去了绑定任意属性的便利,但是因为每一个实例没有__dict__属性,却能有效节省每一个实例的内存消耗,有利于生成小而精干的实例。
4、新式类增加了__getattribute__方法
# -*- coding:utf-8 -*-
class A():
def __getattribute__(self, *args, **kwargs):
print "A.__getattribute__"
class A1(object):
def __getattribute__(self, *args, **kwargs):
print "A1.__getattribute__"
a = A()
a1 = A1()
a1.test
print "------"
a.test
输出:
A1.__getattribute__
Traceback (most recent call last):
------
File "xxx/new_old_class.py", line 20, in <module>
a.test
AttributeError: A instance has no attribute 'test'
可以看出A1是新式类,每次通过实例访问属性,都会经过__getattribute__函数;
A不会调用__getattribute__所以出错了
参考:
https://www.zhihu.com/question/22475395
https://blog.csdn.net/u010066807/article/details/46896835