自学Python 29 模块架构

Python 模块架构

  因为Python是一门面向对象的编程语言,所以也遵循了模块架构程序的编程原则。

一、最基础的模块调用

  在前面的文章中,已经详细了解了和模块化开发相关的基本知识,例如在下面的实例中,演示了在程序中调用外部模块文件的过程:

import math         #导入math模块,math模块是标准库中的,所以不用安装,可以直接使用
from math import sqrt       #从math模块中导入sqrt()函数
import math as shuxue       #导入math模块,并将此模块命名为shuxue
print("下面是数学函数:")
print("调用math.sqrt:\t",math.sqrt(9))        #调用math模块中的调用sqrt()函数
print("直接调用sqrt:\t",sqrt(4))        #直接调用sqrt()函数
print("调用shuxue.sqrt:\t",shuxue.sqrt(6))        #等价于调用math模块中的调用sqrt()函数

  在上述代码中,分别使用三种不同的方式导入了math模块或其中的函数,然后分别以三种不同的方式导入对象。虽然被导入的都是同一个模块或模块中的内容(都是调用了系统内置函数中的math.sqrt()方法),但相互之间并不冲突。执行结果是:

  在Python程序中,不能随便导入编写好的外部模块,只有被Python找到的模块才能被导入。如果自己编写的外部模块文件和调用文件处于同一个目录中,那么可以不需要特殊设置就能被Python找到并导入。但是如果两个文件不在同一个目录呢?例如下面的实例中分别编写了外部调用模块文件module_test.py和测试文件but.py,但是这两个文件不是在同一个目录中。
外部模块module_test.py的具体实现代码如下:

print("导入的测试模块的输出")
name ="module_test"
def m_t_pr():
    print("模块module_test中的m_t_pr()函数")

在测试文件but.py中,调用模块代码如下:

import module_test
module_test.m_t_pr()
print("使用外部模块“module_test”中的变量:",module_test.name)

如果上述两个文件在同一个目录中,如图所示:

执行后输出:

  如果在文件but.py所在目录中新建一个名为module的目录,然后把文件module_test.py保存到module目录中,再次运行文件but.py会引发报错:

二、目录“__ pycache__”

  如果外部模块文件 module_test.py和测试文件but.py在同一个目录中,运行成功后会在本目录中生成一个名为“pycache_”的文件目录,这个目录下还有一个名为“module test cnrthon-38.pyc”的文件。如图所示:

  文件 module_test.cpython-38.pyc是一个可以直接运行的文件,这是 Python将文件module_test.py编译成字节码后的文件,Python可以将程序编译成字节码的形式。对于外部模块文件来说,Python总是在第一次调用后将其编译成字节码的形式,以提高程序的启动速度。
  Python程序在导入外部模块文件时会查找模块的字节码文件,如果存在则将编译版后的模块的修改时间同模块的修改时间进行比较。如果两者的修改时间不同,Python会重新编译这个模块,目的是确保两者的内容
容相符。
  在开发Python程序过程中,如果不想将某个源文件发布,此时可以发布编译后的程序(例如上面的文件 module_test.cpython-36.pyc),这样可以起到一定的保护源文件的作用。对于不作为模块来使用的Python程序来说,Python不会在运行脚本后将其编译成字节码的形式。如果想将其编译,可以使用compile模块实现。
例如在下面的实例代码中,将文件mokuai.py进行了编译操作。

import py_compile       #调用系统内置模块py_compile
py_compile.compile("mokuai.py","mokuai.py")     #调用内置函数mokuai()

  在上述代码中,首先使用import语句调用系统内置模块py_compile,然后调用里面的内置库函数compile(),将同目录下的文件mokuai.py编译成文件mokuai.pyc。执行后将会在同录下生成一个名为“mokuai.pvc”的文件,如图所示:

  在Python 3语法规范中规定,如果在方法py_compile.compile中不指定第二个参数,则会在当前目录中新建一个名为“pycache”的目录,并在这个目录中生成如下格式的pyc字节码文件。

被编译模块名.cpython-38.pyc

  运行文件mouai.pyc后,和单独运行文件mokai.py的执行效果是相同的,编译后生成的文件mokuai.pyc并没有改变程序功能,只是以Python字节码的形式存在而已,起到了个保护源码不被泄露的作用。
  除此之外,还可以使用Python命令行选项实现脚本编译。通常有如下两个Python编译的优化选项。
  ●-O:该选项对脚本的优化程度不大,编译后的脚本以”.pyo”格式为扩展名。凡是以”.pyo”为扩展名的Python字节码都是经过优化处理的。
  ●-OO:该选项对脚本优化处理的程度较大,使用这个选项标志可以使编译后的Python脚本变得更小。但是在使用该选项时可能会导致脚本运行错误,读者需要谨慎使用这个选项。
例如可以通过如下命令行编译成pyo文件。

python -O -m py_ compile file.py

  在上述命令行中,其中的“-m”相当于脚本中的import,这里的“-m py_compil”相当于”import py_ compile”。 如果将上面的“-O”改成“-OO”,则表示删除相应的pyo文件,具体帮助信息可以在控制台中输入“python-h” 命令查看。

三、使用“__ name__”属性

  在Python程序中,当一个程序第一次引入一个模块时, 将会运行主程序。如果想在导入模块时不执行模块中的某一个程序块,可以用“__ name__ ” 属性使该程序块仅在该模块自身运行时执行。在运行每个Python程序时,通过对这个“__ name__ ” 属性值的判断,可以让作为导入模块和独立运行时的程序都可以正确运行。在Python程序中,如果程序作为一个模块被导入, 则其“__ name__”属性设置为模块名。如果程序独立运行,则将其“__ name__”属性设置为“main”。由此可见,可以通过属性“__ name__”来判断程序的运行状态。
例如在下面的实例代码中,演示了使用“__ name__”属性设置测试模块是否能正常运行的过程。

实例文件using_ name.py 的具体实现代码如下所示。

if __name__ == '__main__':      #将"__name__"属性与" __main__”比较
    print('三体飞船在运行')        #程序自身在运行,仅在该模块自身运行时执行
else:
    print('我来自另一模块')        #如果程序是作为一个模块被导入

  在上述代码中,将模块的主要功能以实例的形式保存在if语句中,这样可以方便地测试模块是否能够正常运行,或者发现模块的错误。执行后会显示“三体飞船在运行”,如果输入“import using_ name”,按下回车后则输出“我来自另一模块”。执行后会输出:

  注意:建议读者在命令行模式运行[python using _name.py]命令查看完整运行结果,后面的交互式实例也不例外。   如果想了解模块中所提供的功能(变量名、函数名),可以使用内建的函数dir (模块名)来输出模块中的这些信息,当然也可以不使用模块名参数来列出当运行时中的模块信息。例如可以通过“dir(using. name)”列出模块“using. name”中的信息。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2022年5月21日
下一篇 2022年5月21日

相关推荐