首页 > 技术文章 > Python基础-模块

simple-record 2020-10-15 10:01 原文

Python基础-模块

若从Python解释器退出再进入, 那么定义的所有方法和变量都消失了。为此Python提供了一个办法, 把这些定义存放再文件中, 为一些脚本或者交互式的解释器实例使用, 这个文件称为模块。

模块是一个包含所有你定义的函数和变量的文件,其后缀名为.py。模块可以被别的程序引入,以使用该模块中的函数等功能。在一个模块内部, 模块名(作为一个字符串)可以通过全局变量__name__的值获得。以下示例:

def fib(n):
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

def fib2(n):
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result

现在进入python解释器, 并用以下命令导入该模块

>>> import fibo

在当前的符号列表中, 这些并不会直接进入到定义在fibo函数内的名称;它只是进入到模块名fibo中。你可以用模块名访问这些函数:

>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'

如果你想经常使用某个函数, 你可以把它赋值给一个局部变量:

>>> fib = fibo.fib
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

模块导入

import语句

想使用Python源文件, 只需在另一个源文件里执行import语句,语法如下:

import module1[, module2[,... moduleN]]

当解释器遇到import语句,如果模块在当前的搜索路径就会被导入。

一个模块只会被导入一次,不管执行了多少次import。这样可以防止导入模块被一遍又一遍地执行。

from ... import 语句

Python地from语句可以让你从模块中导入一个指定部分到当前地命名空间中, 语法如下:

from modulename import name1[, name2[, ...nameN]]

例如,要导入模块fibo地fib函数, 使用如下语句:

>>> from fibo import fib, fib2
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

这个声明不会把整个fib模块导入到当前的命名空间中, 只会将fibo里的fib函数引入进来。

from ... import * 语句

把一个模块的所有内容全部导入到当前的命名空间也是可行的, 语法如下:

from modulename import *

这提供了一个简单的方法来导入一个模块的所有项目。然而这种什么不该被过多地使用。

深入模块

模块除了方法定义外,还可以包括可执行的代码。这些代码一般用来初始化这个模块。 这些代码只有在第一次被导入时才会被执行。

每个模块有各自的符号表,在模块内部为所有的函数当作全局符号表来使用。所以,模块的作者可以放心大胆在模块内部使用这些全局变量,而不用担心把其他用户的全局变量搞混。

从另一个方面, 当你确实知道在做什么,你可以通过modulename.itemname这个的表示方法来访问模块内的函数。

模块时可以导入其他模块的。在一个模块(或脚本,或其他地方)的最前面使用import来导入一个模块。被导入的模块名称将被当如当前操作的模块的符号表中。

有一种导入的方法,可以使用import直接报模块内的(函数、变量的)名称导入到当前操作模块。比如:

>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

这种导入方法不会把被导入的模块的名称放入到当前的字符里欸包中(所以在这个例子中,fibo这个名称是没有定义的)。

还有一中方法,可以一次性的把模块中的所有(函数、变量)名称都导入到当前模块的字符表:

>>> from fibo import *
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

这将所有的名称都导入进来。大多数情况, Python程序员不使用这种方法,因为引入的其他来源的命名,很可能覆盖已有的定义。

包是一种管理Python模块命名空间的形式,采用"点模块名称"。

比如一个模块的名称是A.B,那么它表示一个包A中的子模块B。

就好像使用模块的时候, 不用担心不同模块之前的全局变量相互影响已有,采用点模块名称这种形式也不用担心不同库之间的模块重名的情况。

这里给出了一种可能的包结构(在分层的文件系统中):

sound/                          顶层包
      __init__.py               初始化 sound 包
      formats/                  文件格式转换子包
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  声音效果子包
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  filters 子包
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

在导入一个包的时候, Python会分键sys.path中的目录来寻找这个包中包含的子目录。

目录中包含一个叫做__init__.py的文件才会被认作是一个包, 主要是为了避免一些烂俗的名字不小心影响搜索路径中的有效模块。

最简单的情况,放一个空的文件__init__.py就可以了。当然这个文件中也是可以包含一些初始化代码或者为__all__变量赋值。

用户可以每次只导入一个包里的特定模块,比如:

>>> import sound.effects.echo

这将会导入子模块:sound.effect.echo。它必须全面去访问:

sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

还有一种导入子模块的方法是:

from sound.effects import echo

这同样会导入子模块:echo,并且它不需要那些冗长的前缀,所以它可以这样使用:

echo.echofilter(input, output, delay=0.7, atten=4)

还有一种变化就是直接导入一个函数或变量:

from sound.effects.echo import echofilter

同样的,这个方法会导入子模块:echo,并且可以直接使用它的echofilter()函数:

echofilter(input, output, delay=0.7, atten=4)

注意当使用from package import item这种形式的时候, 对应的item既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量。

import语法会首先把item当作包定义的名称,如果没有找到, 在试图按照一个模块去导入。如果还没找到,抛出一个:exc:ImportErro异常。反之,如果使用形如import item.subitem.subsubitem这种导入形式,除了最后一项,都必须是包, 而最后一项则可以是模块或者是包,但不能是类, 函数或者变量的名字。

从一个包中导入*

这种方式导入,可能需要很长事件,导入子模块可能会产生不必要地副作用, 这种副作用只有在显式导入子模块时才会发生。

唯一地解决方法是让包作者提供一个包地显式所有。import语句使用下面地规范:如果一个包地__init__.py代码定义了一个名为__all__的列表,它会被视为在遇到from package import *时应道导入的模块名列表。在发布该包的新版本时, 包作者可以决定是否让此列表保持更新。包作者如果认为从它们的包导入*的操作没有必要被使用,也可以决定不支持此列表。例如, 文件sound/effects/__init__.py可以包含以下代码:

__all__ = ["echo", "surround", "reverse"]

这意味着from sound.effects import *将导入sound包的三个命名子模块。

如果没有定义__all__from sound.effects import *语句不会从包sound.effects中导入所有子模块到当前命名空间;它只确保导入了包sound.effects(可能运行在__init__.py中的初始化代码),然后导入包中定义的任何名称。这包括__init__.py定义的任何名称(以及显式加载的子模块)。它还包括由之前的import语句显式加载的包的任何子模块。

import sound.effects.echo
import sound.effects.surround
from sound.effects import *

在这个示例中, echo和surround模块是在执行from ... import语句时导入到前面命名空间中的, 因为它们定义在sound.effects包中。

虽然某些模块被设计为使用import *时只导出遵循某些模式的名称, 但在生产代码中它仍然被认为是不好的做法。

请记住, 使用from package import specific_submodule没有任何问题!实际上,除非导入的模块需要使用来自不同包的同名子模块, 否则这时推荐的表示法。

子包参考

当包被构造称子包时, 你可以使用绝对导入来引用兄弟包的子模块。例如, 如果模块sound.filters.vocoder需要在sound。effects包中使用echo模块, 它可以使用from sound.effects import echo

还可以使用import语句的from module import name形式编写相对导入。这些导入使用前导点来表示相对导入中涉及的当前包和父包。例如,从surround模块,你可以使用:

from . import echo
from .. import formats
from ..filters import equalizer

请注意,相对导入是基于当前模块的名称进行导入的。由于主模块的名称总是__main__,因此用作Python应用程序主模块的模块必须始终使用绝对导入。

包还提供了一个额外的属性__path__。这时一个目录列表,里面包含的目录都有为这个包服务的__init__.py,你得在其他__init__.py被执行前定义,可以修改这个变量, 用来影响包含在包里得模块和子包。

模块的搜索路径

当一个名为spam的模块被导入时, 解释器首先寻找具有该名称的内置模块。如果没有找到, 然后解释器从sys.path变量给出目录列表里寻找名为spam.py的文件。sys.path初始化有这些目录地址:

  • 包含输入脚本的目录(或者未指定文件时的当前目录)
  • PYTHONPATH(一个包含目录名称的列表,他和shell变量PATH有一样的语法)。
  • 取决于安装的默认设置

Python在解析查找模块的路径时, 按照如下的路径搜索:

1、内建模块(built-in):在按照Python解析器时自动安装,不以文件形式存在。

2、系统的标准模块:安装Python时自动安装,默认放在/Lib/目录下。

3、第三方模块: 使用pip命令进行安装和管理,默认放在/Lib/site-packages/目录下。

4、自定义模块:自己写的模块, 可以放在当前目录,也可以放在任意其他位置。

推荐阅读