Python在2.2之后就有使用一种叫做new style class,即新式类

首先需要说明的是,在python3.X(包括3.0)中,新建类都自动生成为新式类,新式类成为默认值。

(如果不是为了兼容性考虑,建议使用最新版本的python解释环境,毕竟发展是朝向更加标准、清晰走的。)

新式类的定义也就是等同于与经典类的区别: 

1. 第一个区别是在声明时有区别,得到的结果也有不同

# 在python2.7解释环境中
class A: pass    #经典类
class B(object): pass	#在2.X环境中,若声明为新式类需要直接继承object类

a = A()
b = B()

print a
print type(a)
print type(a.__class__)

print b
print type(b)
print type(b.__class__)



结果:

<__main__.A instance at 0x000001B34B1707B8>
<type 'instance'>
__main__.A

<__main__.B object at 0x000001B34B170278>
<class '__main__.B'>
<class '__main__.B'>



而在3.x环境中直接进行定义即为新式类:

# 在python 3.6解释环境中
class C:pass # 新式类为默认值,无需显式继承自object,等同于在python2.X中的语句: class C(object): pass

c = C()
print(c)
print(c.__class__)
print(type(c))

结果:

<__main__.C object at 0x000001B34B16B400>
<class '__main__.C'>
<class '__main__.C'>



2. 新式类的继承顺序较经典类继承顺序发生改变。

经典类的多继承时,属性搜索顺序为:先深入继承树的左侧,再返回开始找右侧,也就是深度优先;

新式类的多继承时,属性搜索顺序为:先找最近超类(父类)从左至右,再深度搜索更高超类,也就是所谓的广度优先。
例:

# ptyhon 3.6解释环境中,新式类广度优先
class A:    x = 1

class B(A):    pass

class C(A):    x = 3

class D(B,C):    pass

d = D()
print(d.x)

结果:

>>> 3

属性的搜索过程:d --> D --> B --> C --> A,



而如果在经典类搜索模式中以上搜索过程就变为:d --> D --> B --> A --> C

# ptyhon 2.7解释环境中,新式类广度优先
class A:    x = 1

class B(A):    pass

class C(A):    x = 3

class D(B,C):    pass

d = D()
print(d.x)

结果:

>>> 1

在经典类中,有一个概念就是钻石搜索模式,所谓的钻石搜索模式就是经典类搜索模式,即上面提到的深度优先原则搜索模式,在看《python学习手册(第四版)》时有一点混乱,所以这里拿出来说一下。


3. 支持__slots__实例属性列表

__slots__中加入的属性是该类生成的实例能够访问和改变的唯一属性(包括从超类__slots__中获得的属性)

# python3.6解释环境,windows系统下
class D:
    __slots__ = ['name','age']
    
d = D()
d.name = 'Dogg Snop'
print(d.name)

d.location = 'Tianjing'
print(d.location)

结果:

Dogg Snop
Traceback (most recent call last):
  File "<pyshell#108>", line 1, in <module>
    d.location = 'Tianjing'
AttributeError: 'D' object has no attribute 'location'

如果属性没有在类的命名空间中使用__slots__指出,那么实例就无法再外部进行赋值使用(即添加新属性)


但是可以使用类名直接进行类属性添加:

D.location = "Tianjing"
print(d.location)

结果:

Tianjing

这个也就是在实例中去掉了__dict__属性,才出现无法再实例中无法添加新属性,但是类名直接添加属性;如果想要让用户添加属性,但是又不想被滥用,则可以在__slots__中添加__dict__属性: __slots__ = [……, '__dict__'],这样用户就无法直接使用d.attrname = attrvalue,而必须使用d.__slots__.__dict__[attrname] = attrvalue,防止意外添加属性导致的属性错误和泛滥。



4. 在新式类中,添加了__getattribute__()方法

# Python3.X解释器中
class A:
    def __getattribute__(self, *args, **kwargs):
        print "A.__getattribute__"  
a = A()
a.test

结果:

>>> A.__getattribute__


# Python 2.X解释器中 
class B:    
    def __getattribute__(self, *args, **kwargs):    
        print "B.__getattribute__"
b = B()
b.test



结果:

Traceback (most recent call last):
  File "<pyshell#109>", line 1, in <module>
    b.test
AttributeError: B instance has no attribute 'test'



总结:新式类和经典类是在Python3.0出现以后产生的一种类的新形势,而在2.X版本中添加新式类的定义形式,主要目的还是为了达到兼容性;如果是最初学习的小白,建议直接使用3.X版本的解释器,毕竟越新越规范。