606c51c54f3560f6908015efaf9139ca
Python的模块实现机制

Python的模块实现机制

使用过Python的同学相信除了被Python简洁的语法使用方式(比如没有恼人的指针)所吸引之外,选择Python的一大原因就是其强大的苦。从科学计算numpy到服务器搭建djangoflask,可谓你想要啥,它就能给你啥。

今天就让我们来探究下Python这些库是如何和Python自身结合起来的。

库的加载与构成

Python中一般将库称为module,哪些东西能包含在module呢?

  • 变量与值,a = 1

  • 函数

    def g():
        print "Hello World"
  • class testclass():
        def g():
            print "Hello World"
  • 其他module

    换句话说,任何的一切能在Python里呈现的,都能包装在一个module里。

任何.py文件都是一个module。

__main__ 模块

写过Python测试的同学肯定对if __name__ == '__main__': 不陌生,这段代码的主要作用主要是让该python文件既可以独立运行,也可以当做模块导入到其他文件。当导入到其他的脚本文件的时候,此时__name__的名字其实是导入模块的名字,不是__main__, main代码里面的就不执行了。

PyModuleObject

那么,在Python的源码中,模块对应的设计究竟是怎么样的?让我们来一起看看PyModuleObject的定义。

typedef struct {
    PyObject_HEAD
    PyObject *md_dict;
} PyModuleObject;

卧槽,是不是很惊讶,我们的模块对象除去公共的引用计数头部PyObject_HEAD,竟然只包含了一个字典指针。

而这些md_dict里面包含了什么呢?我们以大家熟悉的sys模块来举例,大家写代码会经常import sys,然后调用诸如:sys.version这样代码来获取Python的版本号。

那么,sys也是个模块(module),它也只是拥有md_dict这个指针,那它是如何包含这个version属性(我们暂且理解为属性的呢),肯定是有某些流程将属性注入进去,我们顺藤摸瓜可以发现如下的代码:

 m = Py_InitModule3("sys", sys_methods, sys_doc);
if (m == NULL)
    return NULL;
sysdict = PyModule_GetDict(m);

PyDict_SetItemString(sysdict, "stdin", sysin);
PyDict_SetItemString(sysdict, "stdout", sysout);
PyDict_SetItemString(sysdict, "stderr", syserr);
/* Make backup copies for cleanup */
PyDict_SetItemString(sysdict, "__stdin__", sysin);
PyDict_SetItemString(sysdict, "__stdout__", sysout);
PyDict_SetItemString(sysdict, "__stderr__", syserr);
PyDict_SetItemString(sysdict, "__displayhook__",
                     PyDict_GetItemString(sysdict, "displayhook"));
PyDict_SetItemString(sysdict, "__excepthook__",
                     PyDict_GetItemString(sysdict, "excepthook"));
Py_XDECREF(sysin);
Py_XDECREF(sysout);
top Created with Sketch.