Python 元类问题求解 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
caneman
V2EX    Python

Python 元类问题求解

  •  
  •   caneman 2019-06-12 14:56:32 +08:00 2264 次点击
    这是一个创建于 2314 天前的主题,其中的信息可能已经有所发展或是发生改变。
    class Base(type): print('This is Base.') def __new__(cls, name, bases, attrs): print(cls) return type(name, bases, attrs) #return type.__new__(cls, name, bases, attrs) class Parent(object, metaclass=Base): print('This is Parent.') class Child(Parent): print('This is Child.') 

    输出结果如下:

    • This is Base.
    • This is Parent.
    • <class '__main__.Base'>
    • This is Child.

    这个结果我还可以理解,由上往下执行,走到 Parent 的时候,由元类__new__方法中的 type 方法生成一个新类,返回给 Parent,下面的 Child 继承了 Parent 这个类。

    为什么当把return type(name, bases, attrs)换成return type.__new__(cls, name, bases, attrs)的时候会导致下面的结果?

    • This is Base.
    • This is Parent.
    • <class '__main__.Base'>
    • This is Child.
    • <class '__main__.Base'>

    我知道复写type.__new__方法,产生的结果是 Base 这个类的一个实例,但同时这个实例也是一个类对象, 但是我不太理解的是为什么这里 Child 会再次执行 Base 里面的__new__方法,为什么上面(type())的不执行?

    查阅了很多资料,国内的论坛好像很少有讲type.__new__type()的区别的,还是我姿势不对? StackOverflow 和 Python3.7 文档我也看了相关的内容,能理解type.__new__type()的区别了,但是不太明白涉及到这种多重继承的时候type.__new__type()为什么会有差异。

    还是我理解错了?希望有人能帮我解答一下,谢谢!!


    总结一下就是:

    • 采用 type()的写法,会导致 Child 仅仅继承 Parent 类的属性和方法。
    • 采用type.__new__()的写法,会使 Child 类是由 Base 生成的,会覆盖掉 Parent 类中由 Base 生成的部分。

    我想问一下为什么会导致这种差异。

    10 条回复    2019-06-12 16:26:14 +08:00
    mayorbryant
        1
    mayorbryant  
       2019-06-12 15:07:32 +08:00
    super 了解一下
    wwqgtxx
        2
    wwqgtxx  
       2019-06-12 15:10:58 +08:00 via iPhone
    因为 type()是构建了一个新的类,而 type.__new__是创建了一个 type object
    简单的来说,当你直接用 type()的时候,你调用 Base()返回的根本就不是你自己定义的 Base,而且动态定义的一个也叫 Base 的 class
    metaclass 的关键并不是要重载__new__,而是要重载__call__才能改变子类的创造过程,你重载了__new__只是改变了自己的构造过程罢了
    wwqgtxx
        3
    wwqgtxx  
       2019-06-12 15:19:54 +08:00 via iPhone
    仔细看了一下,撤回 2#的回复
    wwqgtxx
        4
    wwqgtxx  
       2019-06-12 15:23:14 +08:00 via iPhone   1
    直接 type()之后返回的 Parent 就不再含有 Base 为自己的 metaclass 信息了(.__metaclass__),而你调用了 type.__new__会附加上,所以 Child 的 metaclass 同样是 Base
    wwqgtxx
        5
    wwqgtxx  
       2019-06-12 15:32:24 +08:00 via iPhone   1
    caneman
        6
    caneman  
    OP
       2019-06-12 15:34:21 +08:00
    @wwqgtxx 明白了,那么`type.__new__`给 Parent 附加上 metaclass 信息具体是在哪个部分实现的?如果我想实现`type.__new__`和 type 具有相同的结果(只针对 metaclass 信息有无这一点),我应该重载哪个部分呢?
    wwqgtxx
        7
    wwqgtxx  
       2019-06-12 15:40:40 +08:00 via iPhone   1
    @caneman 实现就是在 typeobject.c 的 2442 行到 2452 行
    wwqgtxx
        8
    wwqgtxx  
       2019-06-12 15:46:11 +08:00 via iPhone
    正常还是应该重载__new__,然后调用 type.__new__
    之前二楼回答有误,type()和 type.__new__返回的均是一个新的类
    wwqgtxx
        9
    wwqgtxx  
       2019-06-12 15:54:26 +08:00 via iPhone   1
    准确说 type()之后创建了一个 type 的实例,而你调用了 type.__new__创建的是一 Base 的实例(这个实例本身的父类当然还是 type )
    caneman
        10
    caneman  
    OP
       2019-06-12 16:26:14 +08:00
    @wwqgtxx 明白了,谢谢!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     863 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 19:46 PVG 03:46 LAX 12:46 JFK 15:46
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86