Python之经典类VS新式类和Supper

简介: Python之经典类VS新式类和Supper
  • 问题:

把下面代码用python2 和python3都执行一下

#_*_coding:utf-8_*_
class A:
    def __init__(self):
        self.n = 'A'
class B(A):
    # def __init__(self):
    #     self.n = 'B'
    pass
class C(A):
    def __init__(self):
        self.n = 'C'
class D(B,C):
    # def __init__(self):
    #     self.n = 'D'
    pass
obj = D()
print(obj.n)

输出结果

D:\Python\python\python-2.7.13\Python27\python2.exe 
A
D:\Python\python\python-3.6.1\Python36-64\python.exe 
C


  • 原因:
classical vs new style:
经典类:深度优先
新式类:广度优先

1)首先,他们写法不一样:
class A:
    pass
class B(object):
    pass
2)在多继承中,新式类采用广度优先搜索,而旧式类是采用深度优先搜索。
3)新式类更符合OOP编程思想,统一了python中的类型机制。


  • 分析:


从Python2.2开始,Python 引入了 new style class(新式类)

   

新式类跟经典类的差别主要是以下几点:

1. 新式类对象可以直接通过__class__属性获取自身类型:type;
2. 
3. 继承搜索的顺序发生了改变,经典类多继承属性搜索顺序: 先深入继承树左侧,再返回,开始找右侧;新式类多继承属性搜索顺序: 
4. 先水平搜索,然后再向上移动;
5. 
6. 新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中;
7. 
8. 新式类增加了__getattribute__方法;


  • 举例说明
  • 新式类对象可以直接通过__class__属性获取自身类型:type;

# -*- coding:utf-8 -*-
class E:
    # 经典类
    pass
class E1(object):
    # 新式类
    pass
e = E()
print("经典类")
print(e)
print(type(e))
print(e.__class__)
print("新式类")
e1 = E1()
print(e1)
print(type(e1))
print(e1.__class__)


输出结果:


  • pyhon2.7
经典类
<__main__.E instance at 0x0000000002ABF148>
<type 'instance'>
__main__.E
新式类
<__main__.E1 object at 0x0000000002AB65C0>
<class '__main__.E1'>
<class '__main__.E1'>


  • pyhon3.6


经典类
<__main__.E object at 0x000000000267B7F0>
<class '__main__.E'>
<class '__main__.E'>
新式类
<__main__.E1 object at 0x000000000267B3C8>
<class '__main__.E1'>
<class '__main__.E1'>


  • Python 2.x中默认都是经典类,只有显式继承了object才是新式类
  • Python 3.x中默认都是新式类,不必显式的继承object
  • E1是定义的新式类。那么输输出e1的时候,不论是type(e1),还是e1.__class__都是输出的<class '__main__.E1'>。




  • 继承搜索的顺序发生了改变,经典类多继承属性搜索顺序:先深入继承树左侧,再返回,开始找右侧;新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动;

1. # -*- coding:utf-8 -*-
2. class A(object):
3.     """
4.  新式类
5.     作为所有类的基类
6.     """
7.     def foo(self):
8.         print("class A")
9. 
10. class A1():
11.     """
12.   经典类
13.     作为所有类的基类
14.     """
15.     def foo(self):
16.         print("class A1")
17. 
18. 
19. class C(A):
20.     pass
21. 
22. 
23. class C1(A1):
24.     pass
25. 
26. class D(A):
27.     def foo(self):
28.         print("class D")
29. 
30. 
31. class D1(A1):
32.     def foo(self):
33.         print("class D1")
34. 
35. 
36. class E(C, D):
37.     pass
38. 
39. class E1(C1, D1):
40.     pass
41. 
42. e = E()
43. e.foo()
44. 
45. e1 = E1()
46. e1.foo()

  • pyhon2.7
  1. class D
  2. class A1


  • pyhon3.6

  1. class D
  2. class D1


因为A新式类,对于继承A类都是新式类,首先要查找类E中是否有foo(),如果没有则按顺序查找C->D->A。它是一种广度优先查找方式。

因为A1经典类,对于继承A1类都是经典类,首先要查找类E1中是否有foo(),如果没有则按顺序查找C1->A1->D1。它是一种深度优先查找方式。


  • 新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中;

                   比如只允许对A实例添加name和age属性:


  1. # -*- coding:utf-8 -*-
  2. class A(object):
  3.    __slots__ =('name','age')
  4. class A1():
  5.    __slots__ =('name','age')
  6. a1 = A1()
  7. a = A()
  8. a1.name1 ="a1"
  9. a.name1 ="a"
  • pyhon2.7

  1. Traceback(most recent call last):
  2.  File"test.py", line 12,in<module>
  3.    a.name1 ="a"
  4. AttributeError:'A' object has no attribute 'name1'


A是新式类添加了__slots__ 属性,所以只允许添加 name age

A1经典类__slots__ 属性没用,

所以a.name是会出错的


  • pyhon3.6

  1. Traceback(most recent call last):
  2.  File"test.py", line 11,in<module>
  3.    a1.name1 ="a1"
  4. AttributeError:'A1' object has no attribute 'name1'


在python3.x中,

A和

A1都是新式类

  1. 通常每一个实例都会有一个__dict__属性,用来记录实例中所有的属性和方法,也是通过这个字典,可以让实例绑定任意的属性
  2. __slots__属性作用就是,当类C有比较少的变量,而且拥有__slots__属性时,
  3. C的实例就没有__dict__属性,而是把变量的值存在一个固定的地方。如果试图访问一个__slots__中没有
  4. 的属性,实例就会报错。
  5. 这样操作有什么好处呢?__slots__属性虽然令实例失去了绑定任意属性的便利,
  6. 但是因为每一个实例没有__dict__属性,却能有效节省每一个实例的内存消耗,有利于生成小而精
  7. 干的实例。



  • 新式类增加了__getattribute__方法;

  1. class A(object):
  2.    def __getattribute__(self,*args,**kwargs):
  3.        print("A.__getattribute__")
  4. class A1():
  5.    def __getattribute__(self,*args,**kwargs):
  6.        print("A1.__getattribute__")
  7. a1 = A1()
  8. a = A()
  9. a.test
  10. print("=========")
  11. a1.test


  • pyhon2.7

  1. A.__getattribute__
  2. Traceback(most recent call last):
  3. =========
  4.  File"test.py", line 15,in<module>
  5.    a1.test
  6. AttributeError: A1 instance has no attribute 'test'


  • pyhon3.6

  1. A.__getattribute__
  2. =========
  3. A1.__getattribute__

可以看出A是新式类,每次通过实例访问属性,都会经过__getattribute__函数,

A1不会调用__getattribute__所以出错了


总之

  1. Python2.x中默认都是经典类,只有显式继承了object才是新式类
  2. Python3.x中默认都是新式类,不必显式的继承object


super()


  1. super(self,C).func()    #调用的并不是其父类C的func,而是C在MRO中的下一个类的func,
  2. 不能再经典类中使用
  3. 开始一直以为在多重继承的情况下选择执行某个父类的方法,网上有不少也是这么说的(被误导了)。
  4.  
  5. 经典类的MRO(基类搜索顺序)算法是深度优先。
    新式类的MRO算法是C3算法。


  1. class A(object):
  2.    def __init__(self):
  3.        print"A"
  4. class B(object):
  5.    def __init__(self):
  6.        print("B")
  7. class C(object):
  8.    def __init__(self):
  9.        print("C")
  10. class D(A, B, C):
  11.    def __init__(self):
  12.        super(D, self).__init__()
  13.        super(A, self).__init__()
  14.        super(B, self).__init__()
  15.        super(C, self).__init__()
  16. X = D()


输出结果:

  1. A
  2. B
  3. C

会发现:

  1. super(D,self).__init__()  

执行的是A.__init__()


  1. super(A,self).__init__()  

执行的是B.__init__()


  1. super(B,self).__init__()  

执行的是C.__init__()


  1. super(C,self).__init__()  

执行的是Object.__init__()


这是因为mro(D)为:[ D, A, B, C, Object]


目录
相关文章
|
2月前
|
数据采集 缓存 Java
Python vs Java:爬虫任务中的效率比较
Python vs Java:爬虫任务中的效率比较
|
1月前
|
安全 数据库 C++
Python Web框架比较:Django vs Flask vs Pyramid
Python Web框架比较:Django vs Flask vs Pyramid
40 1
|
2月前
|
安全 数据库 C++
Python Web框架比较:Django vs Flask vs Pyramid
Python Web框架比较:Django vs Flask vs Pyramid
34 4
|
2月前
|
索引 Python
python-类属性操作
【10月更文挑战第11天】 python类属性操作列举
22 1
|
2月前
|
Java C++ Python
Python基础---类
【10月更文挑战第10天】Python类的定义
26 2
|
2月前
|
安全 数据库 C++
Python Web框架比较:Django vs Flask vs Pyramid
【10月更文挑战第10天】本文比较了Python中三个最受欢迎的Web框架:Django、Flask和Pyramid。Django以功能全面、文档完善著称,适合快速开发;Flask轻量灵活,易于上手;Pyramid介于两者之间,兼顾灵活性和安全性。选择框架时需考虑项目需求和个人偏好。
37 1
|
2月前
|
安全 数据库 C++
Python Web框架比较:Django vs Flask vs Pyramid
【10月更文挑战第6天】本文比较了Python中三个最受欢迎的Web框架:Django、Flask和Pyramid。Django功能全面,适合快速开发;Flask灵活轻量,易于上手;Pyramid介于两者之间,兼顾灵活性和可扩展性。文章分析了各框架的优缺点,帮助开发者根据项目需求和个人偏好做出合适的选择。
37 4
WK
|
2月前
|
Python
Python类命名
在Python编程中,类命名至关重要,影响代码的可读性和维护性。建议使用大写驼峰命名法(如Employee),确保名称简洁且具描述性,避免使用内置类型名及单字母或数字开头,遵循PEP 8风格指南,保持项目内命名风格一致。
WK
14 0
|
2月前
|
程序员 开发者 Python
深度解析Python中的元编程:从装饰器到自定义类创建工具
【10月更文挑战第5天】在现代软件开发中,元编程是一种高级技术,它允许程序员编写能够生成或修改其他程序的代码。这使得开发者可以更灵活地控制和扩展他们的应用逻辑。Python作为一种动态类型语言,提供了丰富的元编程特性,如装饰器、元类以及动态函数和类的创建等。本文将深入探讨这些特性,并通过具体的代码示例来展示如何有效地利用它们。
39 0
|
2月前
|
Python
Python中的类(一)
Python中的类(一)