123e3b2254e31907203a87c963fe04ff
Python的Package与Module

Python的Package与Module

在上文《Python中import机制的实现原理》上中,我们没有针对load_nextget_parent展开。本文就从这两个函数展开,引出两个重要的概念:PackageModule

lib文件夹说起

了解Python的读者都知道,Python实际上默认带上了一个文件夹,名叫lib,里面包含了一个对应版本的pythonxx.zip,我们可以用如下的代码来确认下:

>>> import sys
>>> sys.path
['', '/Library/Python/2.7/site-packages/pip-8.1.1-py2.7.egg', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip']

这个zip里面是什么呢,解压看一看,如图所示其实就是一堆默认的代码库

这些库内置在Python,大大提升了Python的易用性。

当然,这些库使用前还是需要你import的。

从上述这张图,我们不难看出,库里面有些是py文件,有些又是嵌套着文件夹。这两者有什么区别吗?

简单来说,带有__init.py__的文件夹就是package,文件夹中的xxx.py就是模块,是实际上真正使用python的库

那是不是每个文件夹都默认成为了package呢?答案是否定的,必须带有__init.py__

我们以pydoc_data为例,打开文件夹,发现其中定义着两个如下的文件:

了解了大致的概念,让我们回到之前遗留的两个函数get_parent以及load_next中:

get_parent

static PyObject *
get_parent(PyObject *globals, char *buf, Py_ssize_t *p_buflen, int level)
{
    static PyObject *namestr = NULL;
    static PyObject *pathstr = NULL;
    static PyObject *pkgstr = NULL;
    PyObject *pkgname, *modname, *modpath, *modules, *parent;
    int orig_level = level;

    *buf = '\0';
    *p_buflen = 0;
    pkgname = PyDict_GetItem(globals, pkgstr);

    if ((pkgname != NULL) && (pkgname != Py_None)) {
        /* __package__ is set, so use it */
        Py_ssize_t len;
        len = PyString_GET_SIZE(pkgname);
        strcpy(buf, PyString_AS_STRING(pkgname));
    } else {

        【注意点】
        modname = WeDict_GetItem(globals, namestr);

        modpath = WeDict_GetItem(globals, pathstr);
        if (modpath != NULL) {
            /* __path__ is set, so modname is already the package name */
            Py_ssize_t len = PyString_GET_SIZE(modname);
            int error;
            if (len > MAXPATHLEN) {
                WeErr_SetString(WeExc_ValueError,
                                "Module name too long");
                return NULL;
            }
            strcpy(buf, PyString_AS_STRING(modname));
            error = WeDict_SetItem(globals, pkgstr, modname);
        } else {
            /* Normal module, so work out the package name if any */
            char *start = PyString_AS_STRING(modname);
            char *lastdot = strrchr(start, '.');
            size_t len;
            int error;


            len = lastdot - start;
                            strncpy(buf, start, len);
            buf[len] = '\0';
            pkgname = WeString_FromString(buf);
            error = WeDict_SetItem(globals, pkgstr, pkgname);
            Py_DECREF(pkgname);
        }
top Created with Sketch.