乐趣区

关于python:Python高效编程

“Life is short, I use python” 这句喜闻乐见的宣传语,在某种程度上表白了应用 python 开发软件的高效。以笔者目前的能力来说,python 开发软件的高效次要体现在两个方面:1. 简略且贴合自然语言的语法设计,这使得 python 程序的可读性极佳,可能缩小将逻辑转换为程序,查看逻辑谬误的老本。2.(简直)一切都是对象的形象形式,凭此,软件开发者首先能够将物理世界的客观事物都形象为程序中的对象,而后自在组织及操作。本文将从 python 程序的执行和 python 程序中所有皆为对象两个话题,具体论述笔者对 python 高效编程的浅见。

因自己满腹经纶,故行文之间恐有纰漏,望诸君海涵,不吝赐教,若能予以斧正,则感激不尽。

python 程序的执行


图 1 first.py

有一个 first.py 文件, 内容如图 1 所示。python 解释器执行后,顺次输入 the first file 和 the main function。由此可知,python 解释器是“逐行解释”程序的。


图 2 second.py

在 first.py 的同级目录下增加一个 second.py 文件, 内容如图 2 所示,first.py 的内容更新为图 3 所示。python 解释器执行 first.py 后,顺次输入 the second file,the first file 和 the main function。这阐明,import 语句被最先执行,而且 second.py 不是主 module。此外,同级目录下多了一个__pycache__目录,其内有一个 second.cpython-38.pyc 文件(笔者应用的是 CPython3.8 解释器),它是一个 binary 文件,执行 python second.cpython-38.pyc 后,打印 the second file。由此可知,python 解释器是先编译 second.py,而后将 pyc 文件给 first.py 应用。因而 python 解释器运行 python 程序的过程,蕴含了编译与解释两个阶段。


图 3 更新后的 first.py

从上述内容可知,import 的语义是导入 pyc 文件。那么,python 解释器抛出 ModuleNotFoundError 的本质是,__pycache__的父目录没有被退出到 python 解释器的搜寻门路中。个别地,python 解释器的搜寻门路包含 python 解释器执行的当前目录,规范库及 pip 装置目录,环境变量 PYTHONPATH 以及 sys.path.insert/append 动静增加的目录。
进一步地,python 解释器是如何执行”import second“这条语句的呢?python 官网文档在 importlib 中给出了答案[1]。首先调用__init__.py 文件中的 import_module 函数,而后调用_bootstrap.py 文件中的_gcd_import 函数,最初调用同文件下的_find_and_load 函数,其源码如下图 4 所示。通过源码可知,python 将程序运行所需的所有模块都保留在了 sys.modules 中,它是一个字典。


图 4 _find_and_load 函数源码

python 程序中所有皆为对象

批改 first.py 文件的内容如图 5 所示,python 解释器执行 first.py 后,输入内容如正文所示,这里,咱们先断言它们都是类的实例化对象。如何验证呢?


图 5 first.py

python 提供了__class__属性来获取对象的类。批改 first.py 文件内容如图 6 所示, 拜访它们的__class__后,输入的类如正文所示,由此验证了它们都是对象。而且,输入的这些类与 MyClass 一样,它们仍是类的实例化对象,能够持续拜访__class__属性,输入的类均为 <class ‘type’>。此时,咱们发现 module,function 和 int 的类都是 type,而且 type 的类仍是 type。由此可知,python 的对象体系如图 7 所示,其中 type 被称作 metaclass。


图 6 first.py 的类

联合 python 解释器逐行解释的工作原理可知,def myFunc 通过编译、解释后会被创立为名为 myFunc 的 function 对象,class MyClass 通过编译、解释后会被创立为名为 MyClass 的 class 对象。查阅 python 官网文档可知,类 function 实例化的 function 对象 myFunc 只容许被调用以及作为参数传递,MyClass 则能够实例化 object[2]。而且,Class MyClass 等同于 MyClass = type(‘MyClass’, (), {}),其中 type(className, bases, dict, **kwds)为 type 的一种构造函数[3]。


图 7 python 的对象体系

了解了 python 在宏观层面的对象体系后,咱们将眼光聚焦到对象自身。在 python 中,object 是数据和办法的聚合体, 其中数据与办法的可调用对象, 统称为 object 的属性(attribute),内置函数 dir(object)能够查看 object 的属性,object 调用拜访符 ”.” 能够拜访它的属性。
例如, 在 first.py 的同级目录下增加一个 third.py 文件, 内容如图 8 所示。python 解释器执行 third.py 后,third.py 中的输入内容如图 8 中正文所示。由此可知,module 对象 second,class 对象 MyClass 及 function 对象 myFunc,都是 module 对象 first 的属性。在 third.py 中应用 first.XXX 即可拜访它们。通过属性__module__,对象能够取得它隶属的 module 的名称。


图 8 third.py

除了符号 ”.” 以外,python 还提供了内置函数 getattr(object, name),可能通过字符串映射到 object 的属性。与之绝对地,内置函数 setattr(object, name, value)则用于更新属性的值, 这就是 python 的反射机制。因为 python 程序中简直所有皆为对象,所以熟练掌握这些内置函数后,软件开发者可能轻松实现 基于字符串的事件驱动。

至此,咱们梳理一下上述内容:
1. 解释器逐行解释 python 程序。
2. python 文件被 import 后,会被 python 解释器转换成 module 对象。
3. 所有 module 对象被演绎在 sys.modules 字典内,key 是 moudle 对象的名称。
4. python 文件内的 class 对象,function 对象,根本数值对象,module 对象,都是该 python 文件被转换后的 module 对象的属性。
5. __class__属性能够获取对象的 class 对象,__module__属性能够获取对象隶属模块的名称。
6. 内置函数 getattr 和 setattr 实现了以字符串映射到 object 的属性。

实践上,基于以上 6 点内容,咱们能够从任意 python 对象登程,获取到 python 程序中的其余已被解释器实例化的任意对象。比方,从任意 python 对象推得其隶属的 module 对象,而后获取属性 module,最初拜访属性 module 内的对象。或者借助 sys.modules,绕过 import 语句,间接拜访其余 module 内的 python 对象。

python 解释器的解释程序和 python 程序中所有皆为对象的形象形式,赋予了软件开发者自在编排、更改 python 程序行为的能力。在此基础上,软件开发者再联合设计模式,开发教训以及大量练习,就能够实现高效、简洁、表达能力强的 python 程序。

参考文献
[1] https://docs.python.org/3/lib…
[2] https://docs.python.org/3/lib…
[3] https://docs.python.org/3/lib…

退出移动版