python 经典类和新式类

DAY 12. python新式类和旧式类

继承自object基类的类叫做新式类,否则叫做旧式类,python3中的类默认是新式类,之前版本默认是旧式类

root@kail:~# python
python 2.7.15 (default,Jul 28 2018,11:29:29)
[GCC 8.1.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class A():
...     pass
...
>>> a=A()
>>> dir(a)
['__doc__','__module__']

如上,在python2中定义一个类,不继承任何基类,内建属性只有两个,这就是旧式类,如果想要创建一个新式类,需要显式的继承object基类,如:

root@kail:~# python
python 2.7.15 (default,Jul 28 2018,11:29:29)
[GCC 8.1.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class A(object):
...     pass
...
>>> dir(A)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

新式类默认有很多属性,都是从object基类中继承过来的,而在python3中所有类默认继承object基类

Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> class A:
        pass
>>> dir(A)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>>

每个属性的具体用法参见Python——特殊属性与方法

12.1 新式类和旧式类的区别

  1. 根本区别:新式类继承自object基类,旧式类不继承任何基类
  2. MRO不同:新式类和经典类的方法解析顺序(MRO)不同,经典类使用DFS,新式类使用C3算法

python 2.7

class A():
    name = 'A'
    age = 12

class B():
    name = 'B'

class C():
    name = 'C'

class D(A,B):
    name = 'D'

class E(A,C):
    name = 'E'
    age = 13

class F(D,E):
    pass

print F.name  # D
print F.age  # 12

上面的继承关系是:

A,age=12
D
B
A
E,age=13
C
F

显然在age的继承上,2.7使用了DFS,我们再看3.7

python 3.7

class A():
    name = 'A'
    age = 12

class B():
    name = 'B'

class C():
    name = 'C'

class D(A,B):
    name = 'D'

class E(A,C):
    name = 'E'
    age = 13

class F(D,E):
    pass

print(F.name)  # D
print(F.age)  # 13

显然3.7没有使用DFS,而是在每一次寻找入度为零的节点,加入mro列表后删除这条边,再次寻找,以上面的代码为例,第一个入读为0的节点就是F,所以mro表的第一项就是F,删除F及相连的边,入度为0的就是DE,按照书写代码的顺序第二项为D,第三项为E,依次,最终所有新式类继承自object,所以最后一项就是object,继承顺序就是按mro列表的顺序来的,可以使用mro()查看mro列表

print(F.mro())
# [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>]

也就是说,C3是先在水平方向上查找,再往上查找

12.2 总结

基类MRO备注
经典类NoneDFSpython2默认经典类
新式类objectC3python3默认新式类

我尝试在python3中通过重写type元类写出经典类,但发现这样写出的类似乎不是真的经典类,只是默认属性和经典类差不多,MRO行为依旧和新式类一样,可能是我代码有问题,请各位大佬赐教

class Type(type):
    __bases__ = ()
    __base__ = None
    __mro__ = (None,)



Foo1 = Type('Foo1',() ,{})
Foo2 = Type('Foo2', (), {})
Foo3 = Type('Foo3', (), {})
Foo4 = Type('Foo4', (Foo1, Foo2), {})
Foo5 = Type('Foo5', (Foo1, Foo3), {})
Foo6 = Type('Foo6', (Foo4, Foo5), {})

if __name__ == '__main__':
    
    # base 为空时会多出两个属性,第一个与类描述有关,第二个与弱拷贝有关
    print(dir(Foo1))  # ['__dict__', '__doc__', '__module__', '__weakref__']
    print(dir(Foo2))  # ['__dict__', '__doc__', '__module__', '__weakref__']
    print(dir(Foo3))  # ['__dict__', '__doc__', '__module__', '__weakref__']
    
    # base 不为空时,默认属性表现的和经典类一样
    print(dir(Foo4))  # ['__doc__', '__module__']
    print(dir(Foo5))  # ['__doc__', '__module__']
    print(dir(Foo6))  # ['__doc__', '__module__']
    
    # 假如定义的是经典类,这里应该不能调用mro方法,但这里调用了,说明本身就不对,并且mro列表最后是object,进一步说明这还是一个新式类
    print(Foo1.mro())  # [<class '__main__.Foo1'>, <class 'object'>]
    print(Foo2.mro())  # [<class '__main__.Foo1'>, <class 'object'>]
    print(Foo3.mro())  # [<class '__main__.Foo1'>, <class 'object'>]
    print(Foo4.mro())  # [<class '__main__.Foo4'>, <class '__main__.Foo1'>, <class '__main__.Foo2'>, <class 'object'>]
    print(Foo5.mro())  # [<class '__main__.Foo5'>, <class '__main__.Foo1'>, <class '__main__.Foo3'>, <class 'object'>]
    
    # 清楚的看到MRO使用的是C3算法
    print(Foo6.mro())  # [<class '__main__.Foo6'>, <class '__main__.Foo4'>, <class '__main__.Foo5'>, <class '__main__.Foo1'>, <class '__main__.Foo2'>, <class '__main__.Foo3'>, <class 'object'>]
    
    # TODO: 如何在python3中定义经典类,还是根本不能定义,抛砖引玉,请赐教

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Junebao

如果你碰巧财力雄厚的话...

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值