Python程序设计开发宝典
上QQ阅读APP看书,第一时间看更新

1.7 标准库与扩展库中对象的导入与使用

Python默认安装仅包含基本或核心模块,启动时也仅加载了基本模块,在需要时再显式地导入和加载标准库和第三方扩展库,这样可以减小程序运行的压力,并且具有很强的可扩展性。从“木桶原理”的角度来看,这样的设计与安全配置时遵循的“最小权限”原则是一致的,也有助于提高系统安全性。如果需要的话,可以使用sys.modules.items()显示所有预加载模块的相关信息。另外,可以使用sys.builtin_module_names查看那些编译进Python解释器的模块名字,这些模块具有最快的访问速度和最高的执行效率。

当以模块形式导入.py或.pyw源文件时,系统会自动检查__pycache__文件夹中是否存在相应的.pyc文件,如果有且签名一致则自动从.pyc文件导入以提高加载速度,如果源文件具有比.pyc文件更新的签名,那么导入时会自动重新生成.pyc文件。但需注意的是,如果源文件不存在,导入时不会检查__pycache__文件夹。因此,如果想实现无源码部署,应该把所有.pyc文件放到源文件的文件夹中而不是__pycache__文件夹中。

1.7.1 import模块名 [as别名]

使用这种方式导入以后,使用时需要在对象之前加上模块名作为前缀,必须以“模块名.对象名”的形式进行访问。如果模块名字很长的话,可以为导入的模块设置一个别名,然后使用“别名.对象名”的方式来使用其中的对象。

        >>>import math                     #导入标准库math
        >>>math.sin(0.5)                   #求0.5(单位是弧度)的正弦
        0.479425538604203
        >>>import random                   #导入标准库random
        >>>n=random.random()               #获得[0,1)内的随机小数
        >>>n=random.randint(1,100)         #获得[1,100]区间上的随机整数
        >>>n=random.randrange(1,100)       #返回[1,100)区间中的随机整数
        >>>import os.path as path          #导入标准库os.path,并设置别名为path
        >>>path.isfile(r'C:\windows\notepad.exe')
        True
        >>>import numpy as np              #导入扩展库numpy,并设置别名为np
        >>>a=np.array((1,2,3,4))           #通过模块的别名来访问其中的对象
        >>>a
        array([1,2,3,4])
        >>>print(a)
        [1 2 3 4]

1.7.2 from模块名import对象名[as别名]

使用这种方式仅导入明确指定的对象,并且可以为导入的对象确定一个别名。这种导入方式可以减少查询次数,提高访问速度,同时也可以减少程序员需要输入的代码量,不需要使用模块名作为前缀。

        >>>from math import sin             #只导入模块中的指定对象
        >>>sin(3)
        0.1411200080598672
        >>>from math import sin as f        #给导入的对象起个别名
        >>>f(3)
        0.1411200080598672
        >>>from os.path import isfile
        >>>isfile(r'C:\windows\notepad.exe')
        True

1.7.3 from模块名import*

这是上面用法的一种极端情况,可以一次导入模块中通过__all__变量指定的所有对象。

      >>>from math import*             #导入标准库math中所有对象
      >>>gcd(36,18)                    #最大公约数
      18
      >>>pi                            #常数π
      3.141592653589793
      >>>e                             #常数e
      2.718281828459045
      >>>log2(8)                       #计算以2为底的对数值
      3.0
      >>>log10(100)                    #计算以10为底的对数值
      2.0
      >>>radians(180)                  #把角度转换为弧度
      3.141592653589793

这种方式简单粗暴,写起来也比较省事,可以直接使用模块中的所有对象而不需要再使用模块名作为前缀。但一般并不推荐这样使用。一方面这样会降低代码的可读性,有时候很难区分自定义函数和从模块中导入的函数;另一方面,这种导入对象的方式将会导致命名空间的混乱。如果多个模块中有同名的对象,只有最后一个导入的模块中的对象是有效的,而之前导入的模块中的同名对象都将无法访问,不利于代码的理解和维护。例如,a.py文件中内容如下:

        def test():
            print('test in a.py')

b.py文件中内容如下:

        def test():
            print('test in b.py')

导入a模块以后,test()方法是可用的,而导入b模块之后a模块中的test()方法就无法使用了。例如:

      >>>from a import*
      >>>test()
      test in a.py
      >>>from b import*               #这会导致a模块中的test()函数无法使用
      >>>test()
      test in b.py

1.7.4 模块导入时的搜索路径

不管以哪种形式导入模块并使用其中的对象,Python首先在当前目录中查找模块文件,如果没有找到则从sys模块的path变量所指定的目录中查找,如果仍没有找到则抛出异常提示模块不存在。可以查看sys模块中path变量的值来获知Python导入模块时搜索模块的路径,也可以使用append()方法向其中添加自定义的文件夹以扩展搜索路径。另外,在导入模块时,会优先导入相应的.pyc文件(.py或.pyw伪编译后生成的字节码文件),如果相应的.pyc文件与.py文件时间不相符或不存在对应的.pyc文件,则导入.py文件,同时生成.pyc文件。

Python还支持从zip文件中导入模块。假设当前文件夹中有个内含Vector3.py文件的testZip.zip文件,首先导入sys模块,然后执行sys.path.append('testZip.zip'),然后即可导入Vector3.py文件作为模块来使用。

        >>>import sys
        >>>sys.path.append('testZip.zip')
        >>>import Vector3
        >>>Vector3.__file__               #查看已导入模块对应的程序文件
        'testZip.zip\\Vector3.py'

最后,按照Python编码规范,一般建议每个import语句只导入一个模块,并且要按照标准库、扩展库、自定义库的顺序进行导入。