查看之前的PyObject以及PyVarObject结构,我们会发觉它十分简单,甚至简单的不像话,可能我们会想明明在Python中学的是基类是object
,有着各种各样的属性
['__class__', '__delattr__', '__dir__', ...... ,'__setattr__', '__sizeof__', '__str__']
但是在PyObject中却什么都看不到,其实是有的,只不过是放在了ob_type
里面,它是struct _typeobject
指针,也就是PyTypeObject
指针,我们来看一下Python中的object
所对应的ob_type
在Objects/typeobject.c
中
// 只列出一部分,剩余部分还涉及其它东西,没有看呢
PyTypeObject PyBaseObject_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"object", /* tp_name */
object_repr, /* tp_repr */
object_str, /* tp_str */
PyDoc_STR("object()\n--\n\nThe most base type"), /* tp_doc */
......
};
它的里面包含了各种各样的信息,比如类的名字,对象占用空间的大小,转换为string的方法,都在它里面,
-
tp_name
对应的就是类的名字,当你使用type()
函数的时候就会出现类的名字,假设我们将它改为"oo"
那么,当在新生成的python解释器运行的时候,就会出现:
>>> type(object())
<class 'oo'>
-
tp_str
对应的是执行str()
时调用的,它是一个函数指针,对应的函数如下,可以看出它实际是找到对应的类型对象,然后调用tp_repr
指向的函数或者是object_repr
,在这里它指的都是
static PyObject * object_str(PyObject *self)
{
unaryfunc f;
f = Py_TYPE(self)->tp_repr;
if (f == NULL)
f = object_repr;
return f(self);
}
static PyObject * object_repr(PyObject *self)
{
PyTypeObject *type;
PyObject *mod, *name, *rtn;
// ......
if (mod != NULL && !_PyUnicode_EqualToASCIIId(mod, &PyId_builtins))
rtn = PyUnicode_FromFormat("<%U.%U object at %p>", mod, name, self);
else
rtn = PyUnicode_FromFormat("<%s object at %p>",
type->tp_name, self);
// ......
return rtn;
}
此时对比一下使用str()
时的结果,就可以看出它算是怎么做出rtn
的
>>> str(object())
'<object object at 0x00000239682FB0D0>'
人为的在return
语句之前自己写一条,就可以出现自己想要的输出了,例如:
//else语句修改为
rtn = PyUnicode_FromFormat("<%s object at ???>", "MyObject");
// 输出
>>> str(object())
'<MyObject object at ???>'
-
最后一个
tp_doc
,用到一个宏,但是这个宏其实什么都没做,只是相当于说明一下它是个文档说明的字符串#define PyDoc_STR(str) str
,同样的,我们也可以做修改,通过object.__doc__
或者建object对象访问__doc__
属性就可以看到你的修改结果了不过这里有个小问题,显示的时候明明没有
object()\n--\n\n
这一部分,而且完全删去了也没有任何影响于是我找到了这样一行代码,我猜测它所谓的Signature就是指
tp_name + '()\n--\n\n'
,如果只删除其中部分字符,他就没有办法取出Signature,而正常情况下它会去除掉Signature部分,所以只剩下'The most base type'
这一句话怎么找到的代码是我看了Philip Guo后突然想到的,和我之前介绍的字节码查看有点关系哦,当然,之后会有介绍的
const char *old_doc = _PyType_DocWithoutSignature(type->tp_name,
type->tp_doc);
小小的修改一下,虽然改的东西是最浅显的,但是至少可以知道自己读对了,同时也减少Python解释器源码的神秘感,给自己点信心喽!