python教程(十)模块

模块

目录

简介

  • 以脚本方式执行模块

  • 模块搜索路径

标准模块

dir()函数

  • 从包中导入*

  • 子包参考

简介

如果你从Python解释器退出并再次进入,之前的定义(函数和变量)都会丢失。因此,如果你想编写一个稍长些的程序,最好使用文本编辑器为解释器准备输入并将该文件作为输入运行。这被称作编写 脚本 。随着程序变得越来越长,你或许会想把它拆分成几个文件,以方便维护。你亦或想在不同的程序中使用一个便捷的函数, 而不必把这个函数复制到每一个程序中去。

为支持这些,Python有一种方法可以把定义放在一个文件里,并在脚本或解释器的交互式实例中使用它们。这样的文件被称作 模块 ;模块中的定义可以 导入 到其它模块或者  模块

模块是一个包含Python定义和语句的文件。文件名就是模块名后跟文件后缀.py。在一个模块内部,模块名(作为一个字符串)可以通过全局变量__name__的值获得。例如,创建fibo.py文件,文件中含有以下内容:

# Fibonacci numbers module

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

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

进入Python解释器,用以下命令导入该模块:

import fibo

这并不会直接进入定义在fibo函数内的名称,仅仅进入到模块名fibo中。你可以用模块名访问这些函数:

fibo.fib(1000)#0 1 1 2 3 4 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语句中被导入时才执行。

每个模块都有它自己的私有符号表,该表用作模块中定义的所有函数的全局符号表。因此,模块的作者可以再模块内使用全局变量,而不必担心与用户的全局变量发生意外冲突。

模块可以导入其他模块。习惯上把所有import语句放在模块开头。被导入的模块名存放在调入模块的全局符号表中。

import语句有一个变体,它可以把名字从一个被调模块内直接导入到现模块的符号表里。

例如:
 

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

这并不会把被调模块名引入到局部变量表里(在这个例子里,fibo未被定义)

还有一个变体可以导入模块内定义的所有名称:

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

这会调入所有非以下划线(_)开头的名称。在大多数情况下,Python程序员都不会使用这个功能,因为它在解释器中引入了一组未知的名称,而它们很可能会覆盖一些你已经定义过的东西。

注意通常情况下从一个模块或者包内调入 * 的做法是不太被接受的, 因为这通常会导致代码的可读性很差。

如果模块名称之后带有as,则跟在as之后的名称将直接绑定到所导入的模块。

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

注解:出于效率考虑,每个模块在每个解释器会话中只被导入一次。因此,如果你更改了你的模块,则必须重新启动解释器,或者,如果它只是一个要交互式地测试的模块,请使用importlib.reload(),例如import importlib;importlib.reload(modulename)

以脚本方式执行模块

当你用下面方式运行一个Python模块:

python fibo.py <arguments>

模块里的代码会被执行,就像你导入了模块一样,但是__name__被赋值为‘__main__’。这意味着通过在你的模块末尾添加这些代码:

if __name__ == ''__main__:
    import sys
    fib(int(sys.argv[1]))

你既可以把这个文件当做脚本又可当做一个可调入的模块来使用,因为那段解析命令行的代码只有在当模块是以‘main’文件的方式执行的时候才会运行:

python fibo.py 50

如果这些模块是被导入的,那些代码是不运行的:

import fibo

模块搜索路径

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

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

注解:包含符号链接的目录并没有被添加到模块的搜索路径。

在初始化后,Python程序可以更改sys.path。包含正在运行脚本的文件目录被放在搜索路径的开头处,在标准库路径之前。这意味着将加载此目录里的脚本,而不是标准库中的同名模块。除非有意更换,否则这是错误。更多信息请参阅标准模块

标准模块

Python附带了一个标准模块库,在单独的文档Python库参考中进行了描述。一些模块内置于解释器中;它们提供对不属于语言核心但仍然内置的操作的访问,以提高效率或提供对系统调用等操作系统原语的访问。这些模块的集合是一个配置选项,它也取决于底层平台。例如,winreg 模块只在Windows操作系统上提供。一个特别值得注意的模块 sys,它被内嵌到每一个Python解释器中。

sys.path 变量是一个字符串列表,用于确定解释器的模块搜索路径。该变量被初始化为从环境变量 PYTHONPATH 获取的默认路径,或者如果 PYTHONPATH 未设置,则从内置默认路径初始化。你可以使用标准列表操作对其进行修改:

imports sys
sys.path.append(‘/ufs/guido/lib/python’)

dir()函数

内置函数 dir() 用于查找模块定义的名称。 它返回一个排序过的字符串列表:

import fibo, sys
dir(fibo)#['__name__'m 'fib', 'fib2']

如果没有参数,dir() 会列出你当前定义的名称:

a = [1, 2, 3, 4, 5]
import fibo
fib = fibo.fib
dir()

注意:它列出所有类型的名称:变量,模块,函数,等等。

dir()不会列出内置函数和变量的名称。如果想要这些,它们的定义是在标准模块 builtins 中:

import builtins
dir(builtins)

包是一种通过代用‘带点号的模块名’来构造Python模块命名空间的方法。例如模块名A.B表示A包中名为B的子模块。正如模块的使用使得不同模块的作者不必担心彼此的全局变量名称一样,使用加点的模块名可以使得Numpy或Pillow等多模块软件包的作者不必担心彼此的模块名称一样。

假设你想为声音文件和声音数据的统一处理,设计一个模块集合(一个‘包’)。由于存在很多不同的声音文件格式(通常由于它们的扩展名来识别,例如:.wav,.aiff,.au)因此为了不同文件格式间的转换,你可能需要创建和维护一个不断增长的模块集合。你可能还想对声音数据还做很多不同的处理(例如,混声,添加混声,使用均衡器功能,创建人工立体声效果),因此为了实现这些处理,你将另外写一个无穷尽的模块流。下图所示,可能的包的结构:

sound/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

当导入这个包时,Python搜索sus.path里的目录,查找包的子目录。

必须要有__init__.py文件才能让Python将包含该文件的目录当做包。这样可以防止具有通常名称例如string的目录在无意中隐藏稍后在模块搜索路径上出现的有效模块。在最简单的情况下,__init__.py可以只是一个空文件,但它也可以执行包的初始化代码或设置__all__变量。

包的用户可以从包中导入单个模块,例如:

import sound.effects.echo

这会加载子模块sound.effects.echo。但引用它时必须使用它的全名。

sound.effects.echo.echofilter(input, ouput, 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

另一种形式是直接导入所需的函数或变量:

from sound.effects.echo import echofilter

同样,这也会加载子模块echo,但这会使其函数echofilter()直接可用:

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

请注意,当使用from package import item时,item可以使包的子模块(或子包),也可以是包中定义的其他名称,如函数,类或变量。import语句首先测试是否在包中定义了item;如果没有,它假定它是一个模块并尝试加载它。

吐过找不到他,则引发ImportError异常。

相反,当使用import item.subitem.subsubitem这样的语法时,除了最后一项之外的每一项都必须是一个包;最后一项可以使模块或包,但不能是前一项中定义的类或函数或变量。

 

从包中导入*

当用户写from sound.effects import *人们希望这会以某种方式传递给文件系统,找到包中存在那些子模块,并将它们全部导入。这可能需要很长时间,导入子模块可能会发生不必要的副作用,这种副作用只有在显示导入子模块才会发生。

唯一的解决方案是让包作者提供一个包的显示索引。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(可能运行人何在__inint__.py中的初始化代码),然后导入包中定义的任何名称。这包括__init__.py定义的任何名称。它还包括由之前的import语句显示加载的包的任何子模块。思考下面的代码:

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

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

 

子包参考

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

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

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

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

参考:https://docs.python.org/zh-cn/3/tutorial/modules.html

 

猜你喜欢

转载自blog.csdn.net/tianzhiya121/article/details/89839657