热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

为什么python的异常repr会跟踪传递给__init__的对象?

请看下面的代码片段:In[1]:classA(Exception)::def__init__(self,b):

请看下面的代码片段:

In [1]: class A(Exception):
...: def __init__(self, b):
...: self.message = b.message
...:
In [2]: class B:
...: message = "hello"
...:
In [3]: A(B())
Out[3]: __main__.A(<__main__.B at 0x14af96790>)
In [4]: class A:
...: def __init__(self, b):
...: self.message = b.message
...:
In [5]: A(B())
Out[5]: <__main__.A at 0x10445b0a0>

如果是Afrom 的子类Exception,即使我们只传递了的 message 属性,它也会repr返回一个对 的引用。B()B()

Exception.repr鉴于 cpython 代码不太可读,为什么这是有意的行为,如果可能的话,它如何在 python 伪代码中工作?

回答

创建 Python 对象时__new__,会调用该类的方法,__init__然后在该__new__方法返回的新实例上调用该方法(假设它返回了一个新实例,但有时不会)。

您覆盖的__init__方法没有保留对 的引用b,但您没有覆盖__new__,因此您继承了__new__此处定义的方法(CPython 源链接):

static PyObject *
BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
// ...
if (args) {
self->args = args;
Py_INCREF(args);
return (PyObject *)self;
}
// ...
}

我省略了不相关的部分。如您所见,该类的__new__方法BaseException存储对创建异常时使用的参数元组的引用,因此该元组可用于该__repr__方法打印对用于实例化异常的对象的引用。所以正是这个元组保留了对原始参数的引用b。这与repr应该返回 Python 代码的一般期望一致,该代码将创建处于相同状态的对象(如果可以的话)。

请注意,只有args, notkwds具有此行为;该__new__方法不存储到一个参考kwds__repr__没有打印出来,因此我们预计不会看到相同的行为,如果调用构造函数与关键字参数,而不是一个位置参数。事实上,这就是我们观察到的:

>>> A(B())
A(<__main__.B object at 0x7fa8e7a23860>,)
>>> A(b=B())
A()

有点奇怪,因为这两个A对象应该具有相同的状态,但无论如何代码就是这样编写的。






推荐阅读
author-avatar
feng2502863897
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有