当前位置: 首页 > 后端技术 > Python

Python高效编程

时间:2023-03-26 11:26:31 Python

“人生苦短,我用python”是一句家喻户晓的流行语,某种程度上表达了使用python开发软件的效率。以笔者目前的能力,python开发软件的效率主要体现在两个方面:1.简单自然的语言语法设计,使得python程序的可读性极强,可以减少将逻辑转化为程序,检查成本的逻辑错误。2.(几乎)一切都是对象的抽象方法。基于此,软件开发者可以先将物理世界中的客观事物抽象为程序中的对象,然后再对它们进行自由组织和操作。本文将从python程序的执行和python程序中一切皆对象这两个话题阐述作者对python高效编程的看法。由于本人天赋和学问的欠缺,在写作上可能会有一些错误。希望大家多多包容,不吝赐教。如果你能纠正我,我将不胜感激。python程序的执行图1first.py有一个first.py文件,其内容如图1所示。python解释器执行后,依次输出第一个文件和main函数。可见,python解释器是逐行“解释”程序的。图2second.py在first.py同一目录下添加second.py文件,内容如图2,first.py内容更新如图3。python解释器执行后first。py,它依次输出第二个文件、第一个文件和主函数。这说明先执行了import语句,second.py不是主模块。另外同级目录下多了一个__pycache__目录,里面有一个second.cpython-38.pyc文件(笔者使用的是CPython3.8解释器),是二进制文件,执行pythonsecond.cpython-38.pyc之后,打印第二个文件。由此可见,python解释器先编译second.py,然后对first.py使用pyc文件。因此,python解释器运行一个python程序的过程包括编译和解释两个阶段。图3更新后的first.py从上面的内容来看,import的语义是导入pyc文件。那么,Python解释器抛出ModuleNotFoundError的本质就是__pycache__的父目录没有加入到python解释器的搜索路径中。一般python解释器的搜索路径包括python解释器当前执行目录、标准库和pip安装目录、环境变量PYTHONPATH、sys.path.insert/append动态添加的目录。更进一步,python解释器是如何执行语句“importsecond”的呢?python官方文档在importlib[1]中给出了答案。先调用__init__.py文件中的import_module函数,再调用_bootstrap.py文件中的_gcd_import函数,最后调用同一文件中的_find_and_load函数。源代码如下图4所示。从源码可以看出,python将程序运行所需的所有模块保存在sys.modules中,这是一个字典。图4python程序中的_find_and_load函数源码,一切皆对象。修改first.py文件内容如图5所示,python解释器执行first.py后,输出内容如注释所示。这里,我们首先断言它们都是类的实例化对象。如何验证?图5first.python提供了__class__属性来获取对象的类。修改first.py文件的内容,如图6所示,访问他们的__class__后,输出类如注释所示,从而验证都是对象。而且,这些输出类和MyClass一样,仍然是类的实例化对象,可以继续访问__class__属性,输出类都是。至此,我们发现module、function、int的类都是type,type的类还是type。由此可见,python的对象系统如图7所示,其中type称为元类。图6first.py的class结合python解释器逐行解释的工作原理可以看出,defmyFunc经过编译解释后会被创建为一个名为myFunc的函数对象,classMyClass会被创建为一个编译和解释后名为myFunc的函数对象。MyClass的类对象。根据python官方文档,类函数实例化的函数对象myFunc只允许作为参数调用和传递,而MyClass可以实例化object[2]。此外,ClassMyClass等同于MyClass=type('MyClass',(),{}),其中type(className,bases,dict,**kwds)是类型[3]的构造函数。图7python的对象系统在宏观层面了解了python的对象系统之后,我们关注对象本身。在Python中,对象是数据和方法的集合。数据和方法的可调用对象统称为对象的属性。内置函数dir(object)可以查看对象的属性,对象调用访问器“.”可以访问它的属性。例如在first.py的同级目录下添加一个third.py文件,内容如图8所示。python解释器执行third.py后,third.py中的输出如图中的注释所示8、由此可见,模块对象second、类对象MyClass和函数对象myFunc都是模块对象first的属性。在third.py中使用first.XXX来访问它们。通过属性__module__,对象可以获得所属模块的名称。图8third.py除了符号“.”,python还提供了一个内置函数getattr(object,name),可以通过字符串映射到对象属性。相比之下,内置函数setattr(object,name,value)用于更新属性的值,这是python的反射机制。因为在python程序中几乎所有的东西都是对象,所以软件开发者在掌握了这些内置函数之后,可以很容易地实现基于字符串的事件驱动。至此,我们就把上面的内容梳理一下:1、解释器逐行解释python程序。2.python文件导入后,会被python解释器转换成模块对象。3.所有的模块对象汇总在sys.modules字典中,key是moudle对象的名字。4、python文件中的类对象、函数对象、基本数值对象、模块对象都是python文件转换后的模块对象的属性。5、__class__属性可以得到对象的类对象,__module__属性可以得到对象的下属模块名称。6.内置函数getattr和setattr实现了从字符串映射到对象的属性。理论上,基于以上6点,我们可以从任意一个python对象开始,获取python程序中任何其他已经被解释器实例化过的对象。比如从任意一个python对象推导出其下属模块对象,然后得到属性模块,最后访问属性模块中的对象。或者使用sys.modules绕过import语句,直接访问其他模块中的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...