LAST UPDATE: June 26th 2018, 9:26:42 AM
一切皆对象嘛,好像是OO引申出来的一个概念?(不喜欢,大概因为java(日常无脑黑java)),但是用了这么久Python最大的感受哦确实是这样,那就从object
开始
感觉有关联的应该就是object.h
和object.c
了object.h
有一大段注释,就先看这个了
object.h
文件开头的注释大概记录一下:
- 对象是分配在堆上的结构,有特殊的规则(??)确保对象可正确进行垃圾回收的。
- 对象不会出现静态分配或者分配在栈上的情况,必须通过特殊的宏(变量名?)或者函数来访问。但是
Type
对象是特殊的,标准的type
由静态初始化的type
对象表示。 - 每个对象有一个引用计数用来在指向对象的指针被复制时增加或者被删除时减少。
- 每一个对象有一个
type
,用于确定这个对象代表的是什么和包含的数据是什么类型。类型在对象创建的时候就固定下来。 - 类型本身也是对象,对象有一个指向对应类型对象的指针,类型对象也有一个指向它的类型(元类
type
)的指针,元类type
也有一个指向自己的指针。 - 对象在内存中的大小和地址一旦分配将不会发生变化,如果包含可变大小的数据,可以让对象包含一个指向可变大小部分的指针。相同类型的对象大小不一定一样。这一限制使得对象的引用和操作可以用一个指针简单表示。
- 对象是通过一个
PyObject *
类型的指针来访问的。PyObject
是一个只包含引用计数和类型指针的结构。 - 若对象包含其他数据,则必须等到将指针指向一个指向更长结构类型的指针后才能被访问。这个更长的类型必须以引用计数和类型域开头,
PyObject_HEAD
应该被用在这里。 - A standard interface exists for objects that contain an array of items whose size is determined when the object is allocated.(??)
接下去是一堆基础结构定义
// 定义两个指针,代表一个保存所有存活的堆对象指针的双向链表,这个双向链表只有在DEBUG模式下才会使用
#define _PyObject_HEAD_EXTRA \
struct _object *_ob_next; \
struct _object *_ob_prev;
// 没有对象直接声明为PyObject类型,但每个Python对象指针都能转换为PyObject指针,原理是手动实现继承
// 类似的所有可变大小Python对象指针都能转换为PyVarObject指针
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;
typedef struct {
PyObject ob_base;
Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;
标识符,有点迷,要用把字面量存起来,做什么用?
typedef struct _Py_Identifier {
struct _Py_Identifier *next;
const char* string;
PyObject *object;
} _Py_Identifier;
#define _Py_static_string_init(value) { .next = NULL, .string = value, .object = NULL }
#define _Py_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value)
#define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname)
出现了一堆typedef
,起了一些非常清晰的类型名,比如:
typedef PyObject * (*unaryfunc)(PyObject *); // 一元运算符
typedef PyObject * (*binaryfunc)(PyObject *, PyObject *); // 二元运算符
typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *); // 三元运算符
接下来是buffer
的定义,没看懂,还接了一堆位运算……但是有个数字好像很有趣#define PyBUF_MAX_NDIM 64
,翻了一下缓冲区协议文档,这个数字表示的是存储器表示为n维数组的维数。
然后是PyNumberMethods
,PySequenceMethods
,PyMappingMethods
,PyAsyncMethods
,PyBufferProcs
,前四个定义了数字对象、序列对象、映射对象和异步对象的所有方法,最后一个是缓冲区操作方法。
接下来是一些魔术方法的typedef
,挑几个有代表性的:
typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
typedef PyObject *(*reprfunc)(PyObject *);
typedef Py_hash_t (*hashfunc)(PyObject *);
接下来终于轮到PyTypeObject
了,这东西在typestruct.h
里也有,而且很纯粹,就是在object.h
里把这一段截过去。
// 变量名和注释算是比较详细,大概能了解type对象的组成套路
typedef struct _typeobject {
// 可变大小对象一定要有PyObject_VAR_HEAD,还要放开头
PyObject_VAR_HEAD
const char *tp_name; /* For printing, in format "<module>.<name>" */
// 定长类型的实例大小为tp_basicsize,且tp_itemsize为0
// 变长类型实例的tp_itemsize不为0,必须有ob_size,大小为tp_basicsize + ob_size * tp_itemsize
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
/* Methods to implement standard operations */
destructor tp_dealloc;a // 解构函数
printfunc tp_print; // 用于Python 2.x的print,是一个保留插槽
getattrfunc tp_getattr; // 已弃用
setattrfunc tp_setattr; // 已弃用
PyAsyncMethods *tp_as_async; // 指向一个实现了异步迭代器协议的对象
reprfunc tp_repr; // 用于repr内建函数
// type对象可以作为基本类型,如数字对象或者序列对象或者映射对象,于是把前面定义的方法都塞进去
/* Method suites for standard classes */
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
// 还是基本操作,hash, str, 调用, getattro, setattro
// getattro, setattro 基本和getattr和setattr一样,区别大概在于这两个接受的字符串好象是Python字符串,getattr和setattr接受的是C字符串
/* More standard operations (here for binary compatibility) */
hashfunc tp_hash;
reprfunc tp_str;
ternaryfunc tp_call;
getattrofunc tp_getattro;
setattrofunc tp_setattro;
// type对象可以是缓冲区对象,跟上面一样,这里放了缓冲区的操作方法
/* Functions to access object as input/output buffer */
PyBufferProcs *tp_as_buffer;
// 通过二进制位标识这个类型有什么功能,比如是数字/序列/关联类型,是否可回收等等
// 创建子类的时候这些标识位大部分都逐个被子类继承了
/* Flags to define presence of optional/expanded features */
unsigned long tp_flags;
// 文档字符串
const char *tp_doc; /* Documentation string */
// 用于GC的遍历操作
/* Assigned meaning in release 2.0 */
/* call function for all accessible objects */
traverseproc tp_traverse;
// 用于GC的clear操作
/* delete references to contained objects */
inquiry tp_clear;
// rich comparison 操作
// 包含__lt__, __le__, __eq__, __ne__, __gt__, __ge__
// 普通的comparison操作应该是__cmp__
/* Assigned meaning in release 2.1 */
/* rich comparisons */
richcmpfunc tp_richcompare;
// 弱引用偏移量,类型对象支持弱引用才有用,用于清除
/* weak reference enabler */
Py_ssize_t tp_weaklistoffset;
// 迭代器
/* Iterators */
getiterfunc tp_iter;
iternextfunc tp_iternext;
/* Attribute descriptor and subclassing stuff */
struct PyMethodDef *tp_methods; // 函数定义,定义在methodobject.h
struct PyMemberDef *tp_members; // 属性,定义在structmember.h
struct PyGetSetDef *tp_getset; // 描述符的get/set属性,定义在descrobject.h
struct _typeobject *tp_base; // 指向基类,这个级别只能单继承,多继承需要通过调用元类动态创建类型(?
PyObject *tp_dict; // 对象字典
descrgetfunc tp_descr_get; // 指向描述符__get__函数
descrsetfunc tp_descr_set; // 指向描述符__set__函数
Py_ssize_t tp_dictoffset; // tp_dict 的偏移量
initproc tp_init; // __init__
allocfunc tp_alloc; // 分配内存的函数,应该只由tp_new调用
newfunc tp_new; // __new__
freefunc tp_free; // 指向释放内存的函数
inquiry tp_is_gc; // 指向一个返回1(是)/0(否)的代表是否能进行GC的函数,用于一些类的实例是静态+动态分配出来的时候
PyObject *tp_bases; // 基类元组
PyObject *tp_mro; // 一个包含基类的元组,顺序是按照方法解析顺序排列的
PyObject *tp_cache; // 文档写着Unused....仅供内部使用
PyObject *tp_subclasses; // 子类弱引用列表,也是内部使用
PyObject *tp_weaklist; // 又一个内部使用
destructor tp_del; // 废的内部使用的东西
/* Type attribute cache version tag. Added in version 2.6 */
unsigned int tp_version_tag; // 内部使用...
destructor tp_finalize; // 从Python 3.4开始对应__del__
#ifdef COUNT_ALLOCS
// 这些也是内部使用的
/* these must be last and never explicitly initialized */
Py_ssize_t tp_allocs;
Py_ssize_t tp_frees;
Py_ssize_t tp_maxalloc;
struct _typeobject *tp_prev;
struct _typeobject *tp_next;
#endif
} PyTypeObject;
截至目前(2018.05.13)官方文档并没有tp_version_tag
和tp_del
相关的内容,在这个issue也提到了这两个量没有相关文档tp_version_tag
已经有人验证了是内部使用,至于tp_del
,我提出了自己naive的想法:这个变量对应__del__
然后被Pitrou大佬瞬间教做人:tp_del
废了,用tp_finalize
这位大佬就是提出PEP 442那位,就是在他提议下废了tp_del
这个东西,搞出了tp_finalize
万分荣幸……万分荣幸……
一个大大的饼画完了,总得有人做,接下来的就是这个“做”了。
首先定义一个插槽结构体,对应PyTypeObject
里某个插槽,然后把所有的插槽串在一起放在PyType_Spec
里。
然后还需要把PyTypeSpec
里其他东西设置好,PyType_Spec
这个结构体其实相当于一份清单,要创建的类型名字叫什么,大小是多少,有什么功能,需要用到PyTypeObject
里的什么东西都写在上面。
然后交给PyType_FromSpec
或者PyType_FromSpecWithBases
去创建。
typedef struct{
int slot; /* slot id, see below */
void *pfunc; /* function pointer */
} PyType_Slot;
typedef struct{
const char* name;
int basicsize;
int itemsize;
unsigned int flags;
PyType_Slot *slots; /* terminated by slot==0. */
} PyType_Spec;
PyAPI_FUNC(PyObject*) PyType_FromSpec(PyType_Spec*);
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000
PyAPI_FUNC(PyObject*) PyType_FromSpecWithBases(PyType_Spec*, PyObject*);
#endif
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03040000
PyAPI_FUNC(void*) PyType_GetSlot(PyTypeObject*, int);
#endif
接下来是一个叫做PyHeapTypeObject
,讲道理翻了很久不知道这到底用在哪,只知道PyTypeObject
里的几个Py.+Methods
是指针不是实体,在某些时候指向这里的几个实体;看名字_heaptypeobject
应该是跟堆有关,难道是创建类型时在堆上的结构?
还有一个比较关注的就是下面那段注释:在slotptr
里面处理这几个是很讲究的,有顺序的,因为关联和序列有一些共有的插槽,但必须有个优先顺序,比如__getitem__
必须先以关联来处理。
/* The *real* layout of a type object when allocated on the heap */
typedef struct _heaptypeobject {
/* Note: there's a dependency on the order of these members
in slotptr() in typeobject.c . */
PyTypeObject ht_type;
PyAsyncMethods as_async;
PyNumberMethods as_number;
PyMappingMethods as_mapping;
PySequenceMethods as_sequence; /* as_sequence comes after as_mapping,
so that the mapping wins when both
the mapping and the sequence define
a given operator (e.g. __getitem__).
see add_operators() in typeobject.c . */
PyBufferProcs as_buffer;
PyObject *ht_name, *ht_slots, *ht_qualname;
struct _dictkeysobject *ht_cached_keys;
/* here are optional user slots, followed by the members. */
} PyHeapTypeObject;
之后的全都是函数声明和宏定义,有两个定义在pyport.h
的宏感觉挺常用的,记一下:PyAPI_FUNC(RTYPE)
相当于RTYPE
,特定环境下会导出到dll:__declspec(dllexport) RTYPE
PyAPI_DATA(RTYPE)
相当于extern RTYPE
,特定环境下会导出到dll:extern __declspec(dllexport) RTYPE
这里还定义了type
,object
,super
:
PyAPI_DATA(PyTypeObject) PyType_Type; /* built-in 'type' */
PyAPI_DATA(PyTypeObject) PyBaseObject_Type; /* built-in 'object' */
PyAPI_DATA(PyTypeObject) PySuper_Type; /* built-in 'super' */
接下去是各种标识位,用于tp_flags
,如:Py_TPFLAGS_HAVE_GC
,Py_TPFLAGS_BASETYPE
等
接下来的一部分是引用计数加减的相关操作,都是宏定义Py_INCREF(op)
计数加一Py_RECREF(op)
计数减一,当引用计数减少到0时调用解构函数,有点看不懂这个do...while(0)
……下面还有一些……
#define Py_INCREF(op) ( \
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \
((PyObject *)(op))->ob_refcnt++)
#define _Py_Dealloc(op) ( \
_Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA \
(*Py_TYPE(op)->tp_dealloc)((PyObject *)(op)))
#define Py_DECREF(op) \
do { \
PyObject *_py_decref_tmp = (PyObject *)(op); \
if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \
--(_py_decref_tmp)->ob_refcnt != 0) \
_Py_CHECK_REFCNT(_py_decref_tmp) \
else \
_Py_Dealloc(_py_decref_tmp); \
} while (0)
上面这两个的参数必须不为NULL
,否则用Py_XINCREF/Py_XDECREF
代替
#define Py_XINCREF(op) \
do { \
PyObject *_py_xincref_tmp = (PyObject *)(op); \
if (_py_xincref_tmp != NULL) \
Py_INCREF(_py_xincref_tmp); \
} while (0)
#define Py_XDECREF(op) \
do { \
PyObject *_py_xdecref_tmp = (PyObject *)(op); \
if (_py_xdecref_tmp != NULL) \
Py_DECREF(_py_xdecref_tmp); \
} while (0)
_Py_NewReference(op)
把引用计数设置位1_Py_ForgetReference(op)
删掉一个类型的引用
#define _Py_NewReference(op) ( \
_Py_INC_TPALLOCS(op) _Py_COUNT_ALLOCS_COMMA \
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \
Py_REFCNT(op) = 1)
#define _Py_ForgetReference(op) _Py_INC_TPFREES(op)
Py_CLEAR(op)
可以安全地把op
的计数减一并把op
设为NULL
这里有两句很讲究的代码:先把op
复制一份,然后设置op
为NULL
,最后再把复制体的引用减一
根据自带的注释,这么讲究的原因是:
如果直接Py_XDECREF(op); op = NULL;
,加入第一句已经把op
的引用清空,这是会触发别的代码例如finalize
,这时候GIL交到对应的代码手里,这部分代码可能会对op
对应的东西进行操作,于是导致出现奇奇怪怪的问题。所以正确的方法应该是调用Py_CLEAR
。
#define Py_CLEAR(op) \
do { \
PyObject *_py_tmp = (PyObject *)(op); \
if (_py_tmp != NULL) { \
(op) = NULL; \
Py_DECREF(_py_tmp); \
} \
} while (0)
Py_SETREF(op, op2)
把op
的引用减一并把op
设为op2
,若op
可能为NULL
则应调用Py_XSETREF(op, op2)
具体操作类似于Py_CLEAR
,避免了那个奇奇怪怪的bug
#define Py_SETREF(op, op2) \
do { \
PyObject *_py_tmp = (PyObject *)(op); \
(op) = (op2); \
Py_DECREF(_py_tmp); \
} while (0)
#define Py_XSETREF(op, op2) \
do { \
PyObject *_py_tmp = (PyObject *)(op); \
(op) = (op2); \
Py_XDECREF(_py_tmp); \
} while (0)
开发者们直接假设引用计数不会溢出,因为溢出的时候引用计数已经超过了2**31
引用计数相关的定义到这里就完了,接下来定义了None
和NotImplemented
,配合注释一目了然,这两个是单例实现的
/*
_Py_NoneStruct is an object of undefined type which can be used in contexts
where NULL (nil) is not suitable (since NULL often means 'error').
Don't forget to apply Py_INCREF() when returning this value!!!
*/
PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */
#define Py_None (&_Py_NoneStruct)
/* Macro for returning Py_None from a function */
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
/*
Py_NotImplemented is a singleton used to signal that an operation is
not implemented for a given type combination.
*/
PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */
#define Py_NotImplemented (&_Py_NotImplementedStruct)
/* Macro for returning Py_NotImplemented from a function */
#define Py_RETURN_NOTIMPLEMENTED \
return Py_INCREF(Py_NotImplemented), Py_NotImplemented
最后一个直接翻译过来叫做垃圾桶机制,注释非常详细。
背景:当解构一个对象时,可能会是解构一条长长的链,进而造成栈溢出。
解决方案:设置一个限制,在限制内的可以直接解构,超过限制的先存起来,等不超过限制再解构。
所以是中文译名不是垃圾桶机制还是真的没人介绍这个……完全没有相关中文资料……查出来都是GC的
英文资料也很少,只看到开发大佬在讨论bug……为什么这个没有PEP啊是不是这个从最开始就有了……
#define PyTrash_UNWIND_LEVEL 50
#define Py_TRASHCAN_SAFE_BEGIN(op) \
do { \
PyThreadState *_tstate = PyThreadState_GET(); \
if (_tstate->trash_delete_nesting < PyTrash_UNWIND_LEVEL) { \
++_tstate->trash_delete_nesting;
/* The body of the deallocator is here. */
#define Py_TRASHCAN_SAFE_END(op) \
--_tstate->trash_delete_nesting; \
if (_tstate->trash_delete_later && _tstate->trash_delete_nesting <= 0) \
_PyTrash_thread_destroy_chain(); \
} \
else \
_PyTrash_thread_deposit_object((PyObject*)op); \
} while (0);
object.h
到这里就结束了。
object.c
调试用的不看
开头两个……emmmm通透 =_=
void
Py_IncRef(PyObject *o)
{
Py_XINCREF(o);
}
void
Py_DecRef(PyObject *o)
{
Py_XDECREF(o);
}
接下来几个用于新建对象,稍微调整一下顺序
大概流程是:分配内存,设置[大小]/类型,建引用计数
跟New
函数放在一起看的时候两个Init
函数里检查op == NULL
好像有点多余,是谨慎还是后面有别的函数会直接调用Init
?
PyObject *
PyObject_Init(PyObject *op, PyTypeObject *tp)
{
if (op == NULL)
return PyErr_NoMemory();
/* Any changes should be reflected in PyObject_INIT (objimpl.h) */
Py_TYPE(op) = tp;
_Py_NewReference(op);
return op;
}
PyObject *
_PyObject_New(PyTypeObject *tp)
{
PyObject *op;
op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp));
if (op == NULL)
return PyErr_NoMemory();
return PyObject_INIT(op, tp);
}
PyVarObject *
PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, Py_ssize_t size)
{
if (op == NULL)
return (PyVarObject *) PyErr_NoMemory();
/* Any changes should be reflected in PyObject_INIT_VAR */
op->ob_size = size;
Py_TYPE(op) = tp;
_Py_NewReference((PyObject *)op);
return op;
}
PyVarObject *
_PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems)
{
PyVarObject *op;
const size_t size = _PyObject_VAR_SIZE(tp, nitems);
op = (PyVarObject *) PyObject_MALLOC(size);
if (op == NULL)
return (PyVarObject *)PyErr_NoMemory();
return PyObject_INIT_VAR(op, tp, nitems);
}
下面是调用Finalizer
的两个函数,其中一个是供结构器调用的。
疑问:
PyObject_CallFinalizerFromDealloc
调用PyObject_CallFinalizer
之前为什么要先复活对象?(guess)finalizer
进行操作时对象应该是有效的
tp_finalize
为什么会有复活对象的情况?(solved)- 这个测试解释了可以轻轻松松地用奇奇怪怪的姿势可以让对象复活……
顺便查了一下所有的源码,验证了PyObject_ClaaFinalizer
应该只由PyObject_CallFinalizerFromDealloc
调用这个想法
void
PyObject_CallFinalizer(PyObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
/* The former could happen on heaptypes created from the C API, e.g.
PyType_FromSpec(). */
if (!PyType_HasFeature(tp, Py_TPFLAGS_HAVE_FINALIZE) ||
tp->tp_finalize == NULL)
return;
/* tp_finalize should only be called once. */
if (PyType_IS_GC(tp) && _PyGC_FINALIZED(self))
return;
tp->tp_finalize(self);
if (PyType_IS_GC(tp))
_PyGC_SET_FINALIZED(self, 1);
}
int
PyObject_CallFinalizerFromDealloc(PyObject *self)
{
Py_ssize_t refcnt;
/* Temporarily resurrect the object. */
if (self->ob_refcnt != 0) {
Py_FatalError("PyObject_CallFinalizerFromDealloc called on "
"object with a non-zero refcount");
}
self->ob_refcnt = 1;
PyObject_CallFinalizer(self);
/* Undo the temporary resurrection;
PyObject_CallFinalizer(self);
/* Undo the temporary resurrection can't use DECREF here, it would
* cause a recursive call.
*/
assert(self->ob_refcnt > 0);
if (--self->ob_refcnt == 0)
return 0; /* this is the normal path out */
/* tp_finalize resurrected it! Make it look like the original Py_DECREF
* never happened.
*/
refcnt = self->ob_refcnt;
_Py_NewReference(self);
self->ob_refcnt = refcnt;
if (PyType_IS_GC(Py_TYPE(self))) {
assert(_PyGC_REFS(self) != _PyGC_REFS_UNTRACKED);
}
/* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
* we need to undo that. */
_Py_DEC_REFTOTAL;
/* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
* chain, so no more to do there.
* If COUNT_ALLOCS, the original decref bumped tp_frees, and
* _Py_NewReference bumped tp_allocs: both of those need to be
* undone.
*/
#ifdef COUNT_ALLOCS
--Py_TYPE(self)->tp_frees;
--Py_TYPE(self)->tp_allocs;
#endif
return -1;
}
下面这三个是对一个对象进行print
时调用,调用时检测改对象有没有标识可打印,若有则调用PyObject_Str
,否则调用PyObject_Repr
,这两个结构上基本是一样的,除了PyObject_Str
对应类的__str__
方法,PyObject_Repr
对应类的__repr__
方法,也即调用方法时用的指针不一样,还有__str__
方法没定义时调用PyObject_Repr
输出前会检查要输出的是Bytes
还是Unicode
(PyBytes_Check
, PyUnicode_Check
),若都不是则抛出TypeError
,输出用的是fwrite
int
PyObject_Print(PyObject *op, FILE *fp, int flags)
{
int ret = 0;
if (PyErr_CheckSignals())
return -1;
#ifdef USE_STACKCHECK
if (PyOS_CheckStack()) {
PyErr_SetString(PyExc_MemoryError, "stack overflow");
return -1;
}
#endif
clearerr(fp); /* Clear any previous error condition */
if (op == NULL) {
Py_BEGIN_ALLOW_THREADS
fprintf(fp, "<nil>");
Py_END_ALLOW_THREADS
}
else {
if (op->ob_refcnt <= 0)
/* XXX(twouters) cast refcount to long until %zd isflags
universally available */
Py_BEGIN_ALLOW_THREADS
fprintf(fp, "<refcnt %ld at %p>",
(long)op->ob_refcnt, op);
Py_END_ALLOW_THREADS
else {
PyObject *s;
if (flags & Py_PRINT_RAW)
s = PyObject_Str(op);
else
s = PyObject_Repr(op);
if (s == NULL)
ret = -1;
else if (PyBytes_Check(s)) {
fwrite(PyBytes_AS_STRING(s), 1,
PyBytes_GET_SIZE(s), fp);
}
else if (PyUnicode_Check(s)) {
PyObject *t;
t = PyUnicode_AsEncodedString(s, "utf-8", "backslashreplace");
if (t == NULL)
ret = 0;
else {
fwrite(PyBytes_AS_STRING(t), 1,
PyBytes_GET_SIZE(t), fp);
Py_DECREF(t);
}
}
else {
PyErr_Format(PyExc_TypeError,
"str() or repr() returned '%.100s'",
s->ob_type->tp_name);
ret = -1;
}
Py_XDECREF(s);
}
}
if (ret == 0) {
if (ferror(fp)) {
PyErr_SetFromErrno(PyExc_IOError);
clearerr(fp);
ret = -1;
}
}
return ret;
}
PyObject *
PyObject_Repr(PyObject *v)
{
PyObject *res;
if (PyErr_CheckSignals())
return NULL;
#ifdef USE_STACKCHECK
if (PyOS_CheckStack()) {
PyErr_SetString(PyExc_MemoryError, "stack overflow");
return NULL;
}
#endif
if (v == NULL)
return PyUnicode_FromString("<NULL>");
if (Py_TYPE(v)->tp_repr == NULL)
return PyUnicode_FromFormat("<%s object at %p>",
v->ob_type->tp_name, v);
#ifdef Py_DEBUG
/* PyObject_Repr() must not be called with an exception set,
because it may clear it (directly or indirectly) and so the
caller loses its exception */
assert(!PyErr_Occurred());
#endif
/* It is possible for a type to have a tp_repr representation that loops
infinitely. */
if (Py_EnterRecursiveCall(" while getting the repr of an object"))
return NULL;
res = (*v->ob_type->tp_repr)(v);
Py_LeaveRecursiveCall();
if (res == NULL)
return NULL;
if (!PyUnicode_Check(res)) {
PyErr_Format(PyExc_TypeError,
"__repr__ returned non-string (type %.200s)",
res->ob_type->tp_name);
Py_DECREF(res);
return NULL;
}
#ifndef Py_DEBUG
if (PyUnicode_READY(res) < 0)
return NULL;
#endif
return res;
}
PyObject *
PyObject_Str(PyObject *v)
{
PyObject *res;
if (PyErr_CheckSignals())
return NULL;
#ifdef USE_STACKCHECK
if (PyOS_CheckStack()) {
PyErr_SetString(PyExc_MemoryError, "stack overflow");
return NULL;
}
#endif
if (v == NULL)
return PyUnicode_FromString("<NULL>");
if (PyUnicode_CheckExact(v)) {
#ifndef Py_DEBUG
if (PyUnicode_READY(v) < 0)
return NULL;
#endif
Py_INCREF(v);
return v;
}
if (Py_TYPE(v)->tp_str == NULL)
return PyObject_Repr(v);
#ifdef Py_DEBUG
/* PyObject_Str() must not be called with an exception set,
because it may clear it (directly or indirectly) and so the
caller loses its exception */
assert(!PyErr_Occurred());
#endif
/* It is possible for a type to have a tp_str representation that loops
infinitely. */
if (Py_EnterRecursiveCall(" while getting the str of an object"))
return NULL;
res = (*Py_TYPE(v)->tp_str)(v);
Py_LeaveRecursiveCall();
if (res == NULL)
return NULL;
if (!PyUnicode_Check(res)) {
PyErr_Format(PyExc_TypeError,
"__str__ returned non-string (type %.200s)",
Py_TYPE(res)->tp_name);
Py_DECREF(res);
return NULL;
}
#ifndef Py_DEBUG
if (PyUnicode_READY(res) < 0)
return NULL;
#endif
assert(_PyUnicode_CheckConsistency(res, 1));
return res;
}
下面两个是对应内建函数ascii
和魔术方法__bytes__
的函数PyObject_ASCII
中,先调用对象的repr
方法得到一个Unicode
字符串,然后把Unicode
进行编码,返回一个bytes
对象,转换为Unicode
并返回,在返回的对象中,非ASCII字符已经转为Unicode码PyObject_Bytes
中,通过_PyObject_LookupSpecial
函数用字面量获取对象对应的__bytes__
方法指针,调用,并将结果返回
PyObject *
PyObject_ASCII(PyObject *v)
{
PyObject *repr, *ascii, *res;
repr = PyObject_Repr(v);
if (repr == NULL)
return NULL;
if (PyUnicode_IS_ASCII(repr))
return repr;
/* repr is guaranteed to be a PyUnicode object by PyObject_Repr */
ascii = _PyUnicode_AsASCIIString(repr, "backslashreplace");
Py_DECREF(repr);
if (ascii == NULL)
return NULL;
res = PyUnicode_DecodeASCII(
PyBytes_AS_STRING(ascii),
PyBytes_GET_SIZE(ascii),
NULL);
Py_DECREF(ascii);
return res;
}
PyObject *
PyObject_Bytes(PyObject *v)
{
PyObject *result, *func;
if (v == NULL)
return PyBytes_FromString("<NULL>");
if (PyBytes_CheckExact(v)) {
Py_INCREF(v);
return v;
}
func = _PyObject_LookupSpecial(v, &PyId___bytes__);
if (func != NULL) {
result = PyObject_CallFunctionObjArgs(func, NULL);
Py_DECREF(func);
if (result == NULL)
return NULL;
if (!PyBytes_Check(result)) {
PyErr_Format(PyExc_TypeError,
"__bytes__ returned non-bytes (type %.200s)",
Py_TYPE(result)->tp_name);
Py_DECREF(result);
return NULL;
}
return result;
}
else if (PyErr_Occurred())
return NULL;
return PyBytes_FromObject(v);
}
接下来一大部分是关于rich comparison
的