大师兄的Python源码学习笔记(二十五): 虚拟机中的类机制(

2021-07-23  本文已影响0人  superkmi

大师兄的Python源码学习笔记(二十四): 虚拟机中的类机制(三)
大师兄的Python源码学习笔记(二十六): 虚拟机中的类机制(五)

三. 用户自定义Class

demo.py 

class A(object):
    name = 'A'
    def ___init__(self):
        print('A::__init__')

    def f(self):
        print('A::f')

    def g(self,aValue):
        self.value = aValue
        print(self.value)

a = A()
a.f()
a.g(1)
  1           0 LOAD_BUILD_CLASS
              2 LOAD_CONST               0 (<code object A at 0x000002832FEB9540, file "demo.py", line 1>)
              4 LOAD_CONST               1 ('A')
              6 MAKE_FUNCTION            0
              8 LOAD_CONST               1 ('A')
             10 LOAD_NAME                0 (object)
             12 CALL_FUNCTION            3
             14 STORE_NAME               1 (A)

 13          16 LOAD_NAME                1 (A)
             18 CALL_FUNCTION            0
             20 STORE_NAME               2 (a)

 14          22 LOAD_NAME                2 (a)
             24 LOAD_METHOD              3 (f)
             26 CALL_METHOD              0
             28 POP_TOP

 15          30 LOAD_NAME                2 (a)
             32 LOAD_METHOD              4 (g)
             34 LOAD_CONST               2 (1)
             36 CALL_METHOD              1
             38 POP_TOP
             40 LOAD_CONST               3 (None)
             42 RETURN_VALUE
      code
  1           0 LOAD_NAME                0 (__name__)
              2 STORE_NAME               1 (__module__)
              4 LOAD_CONST               0 ('A')
              6 STORE_NAME               2 (__qualname__)

  2           8 LOAD_CONST               0 ('A')
             10 STORE_NAME               3 (name)

  3          12 LOAD_CONST               1 (<code object ___init__ at 0x000002832FDAD8A0, file "demo.py", line 3>)
             14 LOAD_CONST               2 ('A.___init__')
             16 MAKE_FUNCTION            0
             18 STORE_NAME               4 (___init__)

  6          20 LOAD_CONST               3 (<code object f at 0x000002832FEB90C0, file "demo.py", line 6>)
             22 LOAD_CONST               4 ('A.f')
             24 MAKE_FUNCTION            0
             26 STORE_NAME               5 (f)

  9          28 LOAD_CONST               5 (<code object g at 0x000002832FEB91E0, file "demo.py", line 9>)
             30 LOAD_CONST               6 ('A.g')
             32 MAKE_FUNCTION            0
             34 STORE_NAME               6 (g)
             36 LOAD_CONST               7 (None)
             38 RETURN_VALUE
            code
  4           0 LOAD_GLOBAL              0 (print)
              2 LOAD_CONST               1 ('A::__init__')
              4 CALL_FUNCTION            1
              6 POP_TOP
              8 LOAD_CONST               0 (None)
             10 RETURN_VALUE
            code
  7           0 LOAD_GLOBAL              0 (print)
              2 LOAD_CONST               1 ('A::f')
              4 CALL_FUNCTION            1
              6 POP_TOP
              8 LOAD_CONST               0 (None)
             10 RETURN_VALUE
            code
 10           0 LOAD_FAST                1 (aValue)
              2 LOAD_FAST                0 (self)
              4 STORE_ATTR               0 (value)

 11           6 LOAD_GLOBAL              1 (print)
              8 LOAD_FAST                0 (self)
             10 LOAD_ATTR                0 (value)
             12 CALL_FUNCTION            1
             14 POP_TOP
             16 LOAD_CONST               0 (None)
             18 RETURN_VALUE
  • 声明class A的语句编译后的字节码指令序列存储在与demo.py对应的PyCodeObject对象中。
  • classA的实现代码编译后的字节码指令序列存储在A所对应的PyCodeObject对象中。
1. 创建class对象
1.1 class的动态元信息
  1           0 LOAD_BUILD_CLASS
              2 LOAD_CONST               0 (<code object A at 0x000002832FEB9540, file "demo.py", line 1>)
              4 LOAD_CONST               1 ('A')
              6 MAKE_FUNCTION            0
              8 LOAD_CONST               1 ('A')
             10 LOAD_NAME                0 (object)
             12 CALL_FUNCTION            3
             14 STORE_NAME               1 (A)
ceval.c

        TARGET(LOAD_BUILD_CLASS) {
            _Py_IDENTIFIER(__build_class__);

            PyObject *bc;
            if (PyDict_CheckExact(f->f_builtins)) {
                bc = _PyDict_GetItemId(f->f_builtins, &PyId___build_class__);
                if (bc == NULL) {
                    PyErr_SetString(PyExc_NameError,
                                    "__build_class__ not found");
                    goto error;
                }
                Py_INCREF(bc);
            }
            else {
                PyObject *build_class_str = _PyUnicode_FromId(&PyId___build_class__);
                if (build_class_str == NULL)
                    goto error;
                bc = PyObject_GetItem(f->f_builtins, build_class_str);
                if (bc == NULL) {
                    if (PyErr_ExceptionMatches(PyExc_KeyError))
                        PyErr_SetString(PyExc_NameError,
                                        "__build_class__ not found");
                    goto error;
                }
            }
            PUSH(bc);
            DISPATCH();
        }
  • 在这里,虚拟机所面对的目标从与demo.py对应的PyCodeObject对象,转变为与class A对应的字节码序列:
 1           0 LOAD_NAME                0 (__name__)
             2 STORE_NAME               1 (__module__)
             4 LOAD_CONST               0 ('A')
             6 STORE_NAME               2 (__qualname__)

 2           8 LOAD_CONST               0 ('A')
            10 STORE_NAME               3 (name)

 3          12 LOAD_CONST               1 (<code object ___init__ at 0x000002832FDAD8A0, >file "demo.py", line 3>)
            14 LOAD_CONST               2 ('A.___init__')
            16 MAKE_FUNCTION            0
            18 STORE_NAME               4 (___init__)

 6          20 LOAD_CONST               3 (<code object f at 0x000002832FEB90C0, file >"demo.py", line 6>)
            22 LOAD_CONST               4 ('A.f')
            24 MAKE_FUNCTION            0
            26 STORE_NAME               5 (f)

 9          28 LOAD_CONST               5 (<code object g at 0x000002832FEB91E0, file >"demo.py", line 9>)
            30 LOAD_CONST               6 ('A.g')
            32 MAKE_FUNCTION            0
            34 STORE_NAME               6 (g)
            36 LOAD_CONST               7 (None)
            38 RETURN_VALUE
  • 这里通过LOAD_NAMESTORE_NAME将符号__module__和全局名字空间中符号__name__对应的值关联起来,并放到f_locals中。
  • 通过STORE_NAME和RETURN_VALUE保存命名空间,并将f_locals压入运营时栈,传给CALL_FUNCTION
1.2 metaclass
1.2.1 获得metaclass
Python\bltinmodule.c

static PyObject *
builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
                        PyObject *kwnames)
{
    PyObject *func, *name, *bases, *mkw, *meta, *winner, *prep, *ns, *orig_bases;
     ... ...

        meta = _PyDict_GetItemId(mkw, &PyId_metaclass);
        if (meta != NULL) {
            Py_INCREF(meta);
            if (_PyDict_DelItemId(mkw, &PyId_metaclass) < 0) {
                Py_DECREF(meta);
                Py_DECREF(mkw);
                Py_DECREF(bases);
                return NULL;
            }
            /* metaclass is explicitly given, check if it's indeed a class */
            isclass = PyType_Check(meta);
        }
    }
    if (meta == NULL) {
        /* if there are no bases, use type: */
        if (PyTuple_GET_SIZE(bases) == 0) {
            meta = (PyObject *) (&PyType_Type);
        }
        /* else get the type of the first base */
        else {
            PyObject *base0 = PyTuple_GET_ITEM(bases, 0);
            meta = (PyObject *) (base0->ob_type);
        }
        Py_INCREF(meta);
        isclass = 1;  /* meta is really a class */
    }

    if (isclass) {
        /* meta is really a class, so check for a more derived
           metaclass, or possible metaclass conflicts: */
        winner = (PyObject *)_PyType_CalculateMetaclass((PyTypeObject *)meta,
                                                        bases);
        if (winner == NULL) {
            Py_DECREF(meta);
            Py_XDECREF(mkw);
            Py_DECREF(bases);
            return NULL;
        }
        if (winner != meta) {
            Py_DECREF(meta);
            meta = winner;
            Py_INCREF(meta);
        }
    }
    ... ...
    return cls;
}
Objects\typeobject.c

/* Determine the most derived metatype. */
PyTypeObject *
_PyType_CalculateMetaclass(PyTypeObject *metatype, PyObject *bases)
{
    Py_ssize_t i, nbases;
    PyTypeObject *winner;
    PyObject *tmp;
    PyTypeObject *tmptype;

    /* Determine the proper metatype to deal with this,
       and check for metatype conflicts while we're at it.
       Note that if some other metatype wins to contract,
       it's possible that its instances are not types. */

    nbases = PyTuple_GET_SIZE(bases);
    winner = metatype;
    for (i = 0; i < nbases; i++) {
        tmp = PyTuple_GET_ITEM(bases, i);
        tmptype = Py_TYPE(tmp);
        if (PyType_IsSubtype(winner, tmptype))
            continue;
        if (PyType_IsSubtype(tmptype, winner)) {
            winner = tmptype;
            continue;
        }
        /* else: */
        PyErr_SetString(PyExc_TypeError,
                        "metaclass conflict: "
                        "the metaclass of a derived class "
                        "must be a (non-strict) subclass "
                        "of the metaclasses of all its bases");
        return NULL;
    }
    return winner;
}
1.2.2 调用metaclass
Objects\call.c

PyObject *
PyObject_CallFunctionObjArgs(PyObject *callable, ...)
{
    va_list vargs;
    PyObject *result;

    va_start(vargs, callable);
    result = object_vacall(callable, vargs);
    va_end(vargs);

    return result;
}
Include\object.h

typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
Objects\call.c

PyObject *
PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
{
    ternaryfunc call;
    PyObject *result;

    /* PyObject_Call() must not be called with an exception set,
       because it can clear it (directly or indirectly) and so the
       caller loses its exception */
    assert(!PyErr_Occurred());
    assert(PyTuple_Check(args));
    assert(kwargs == NULL || PyDict_Check(kwargs));

    if (PyFunction_Check(callable)) {
        return _PyFunction_FastCallDict(callable,
                                        &PyTuple_GET_ITEM(args, 0),
                                        PyTuple_GET_SIZE(args),
                                        kwargs);
    }
    else if (PyCFunction_Check(callable)) {
        return PyCFunction_Call(callable, args, kwargs);
    }
    else {
        call = callable->ob_type->tp_call;
        if (call == NULL) {
            PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
                         callable->ob_type->tp_name);
            return NULL;
        }

        if (Py_EnterRecursiveCall(" while calling a Python object"))
            return NULL;

        result = (*call)(callable, args, kwargs);

        Py_LeaveRecursiveCall();

        return _Py_CheckFunctionResult(callable, result, NULL);
    }
}
Objects\typeobject.c

static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    PyObject *obj;
    ... ...
    obj = type->tp_new(type, args, kwds);
    ... ...
    return obj;
}
上一篇 下一篇

猜你喜欢

热点阅读