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]


相关文章
[oeasy]python077_int类型怎么用_整数运算_integer_进制转化_int类
本文主要讲解了Python中`int`类型的应用与特性。首先回顾了`int`词根的溯源,探讨了整型变量的概念及命名规则(如匈牙利命名法)。接着分析了整型变量在内存中的存储位置和地址,并通过`type()`和`id()`函数验证其类型和地址。还介绍了整型变量的运算功能,以及如何通过`int()`函数将字符串转化为整数,支持不同进制间的转换(如二进制转十进制)。此外,文章提及了关键字`del`的使用场景,对比了Python与C语言中`int`的区别,并总结了整型与字符串类型的差异,为后续深入学习奠定基础。
18 1
【03】做一个精美的打飞机小游戏,规划游戏项目目录-分门别类所有的资源-库-类-逻辑-打包为可玩的exe-练习python打包为可执行exe-优雅草卓伊凡-持续更新-分享源代码和游戏包供游玩-1.0.2版本
【03】做一个精美的打飞机小游戏,规划游戏项目目录-分门别类所有的资源-库-类-逻辑-打包为可玩的exe-练习python打包为可执行exe-优雅草卓伊凡-持续更新-分享源代码和游戏包供游玩-1.0.2版本
185 31
【03】做一个精美的打飞机小游戏,规划游戏项目目录-分门别类所有的资源-库-类-逻辑-打包为可玩的exe-练习python打包为可执行exe-优雅草卓伊凡-持续更新-分享源代码和游戏包供游玩-1.0.2版本
Python vs Java:爬虫任务中的效率比较
Python vs Java:爬虫任务中的效率比较
python实战——使用代理IP批量获取手机类电商数据
本文介绍了如何使用代理IP批量获取华为荣耀Magic7 Pro手机在电商网站的商品数据,包括名称、价格、销量和用户评价等。通过Python实现自动化采集,并存储到本地文件中。使用青果网络的代理IP服务,可以提高数据采集的安全性和效率,确保数据的多样性和准确性。文中详细描述了准备工作、API鉴权、代理授权及获取接口的过程,并提供了代码示例,帮助读者快速上手。手机数据来源为京东(item.jd.com),代理IP资源来自青果网络(qg.net)。
Python Web框架比较:Django vs Flask vs Pyramid
Python Web框架比较:Django vs Flask vs Pyramid
87 1
Python Web框架比较:Django vs Flask vs Pyramid
Python Web框架比较:Django vs Flask vs Pyramid
92 4
|
5月前
|
Python基础---类
【10月更文挑战第10天】Python类的定义
75 2
|
5月前
|
python-类属性操作
【10月更文挑战第11天】 python类属性操作列举
54 1
Python Web框架比较:Django vs Flask vs Pyramid
【10月更文挑战第10天】本文比较了Python中三个最受欢迎的Web框架:Django、Flask和Pyramid。Django以功能全面、文档完善著称,适合快速开发;Flask轻量灵活,易于上手;Pyramid介于两者之间,兼顾灵活性和安全性。选择框架时需考虑项目需求和个人偏好。
85 1
Python Web框架比较:Django vs Flask vs Pyramid
【10月更文挑战第6天】本文比较了Python中三个最受欢迎的Web框架:Django、Flask和Pyramid。Django功能全面,适合快速开发;Flask灵活轻量,易于上手;Pyramid介于两者之间,兼顾灵活性和可扩展性。文章分析了各框架的优缺点,帮助开发者根据项目需求和个人偏好做出合适的选择。
138 4

热门文章

最新文章