Python 之模块

模块

如果你从Python解释器中退出并重新输入,你所做的定义(函数和变量)将会丢失。因此,如果你想编写一个稍长的程序,最好使用文本编辑器为解释器准备输入,然后用该文件作为输入来运行它。这被称为创建脚本随着程序变长,您可能需要将其分成几个文件以便于维护。您可能还想使用您在几个程序中编写的方便功能,而不将其定义复制到每个程序中。

为了支持这一点,Python有一种方法可以将定义放在一个文件中,并在脚本或解释器的交互式实例中使用它们。这样的文件被称为 模块 ; 可以将模块中的定义导入到其他模块或模块(在顶层和计算器模式下执行的脚本中可访问的变量集合)。

模块是一个包含Python定义和语句的文件。文件名是带有后缀的模块名称.py在模块中,模块的名称(作为字符串)可用作全局变量的值__name__例如,使用您最喜欢的文本编辑器创建一个fibo.py在当前目录中调用的文件,其中包含以下内容:

# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print b,
        a, b = b, a+b

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

现在输入Python解释器并使用以下命令导入此模块:

>>> import fibo

这不会输入fibo 在当前符号表直接定义的函数的名称它只在fibo那里输入模块名称使用模块名称可以访问这些功能:

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

如果您打算经常使用某个功能,则可以将其分配给本地名称:

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

6.1。更多关于模块

一个模块可以包含可执行语句以及函数定义。这些陈述旨在初始化模块。它们仅在导入语句中遇到一次模块名称时执行[1] (如果文件作为脚本执行,它们也会运行。)

每个模块都有自己的专用符号表,它被模块中定义的所有功能用作全局符号表。因此,模块的作者可以在模块中使用全局变量,而不用担心与用户的全局变量发生意外冲突。另一方面,如果你知道自己在做什么,你可以使用与其功能相同的符号来触摸模块的全局变量modname.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

这会导入除了以下划线(_开头的所有名称

请注意,通常*从模块或包导入的做法是不被接受的,因为它经常导致代码难以读取。但是,可以使用它来保存交互式会话中的输入。

如果模块名称后面跟着as,那么以下名称as将直接绑定到导入的模块。

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

这有效地导入模块的方式与 将要执行的方式相同,唯一的区别在于它可用import fibofib

当使用from类似的效果时,它也可以使用

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

注意

 

出于效率原因,每个模块仅在每个解释器会话中导入一次。因此,如果您更改模块,则必须重新启动解释器 - 或者,如果它只是一个要交互测试的模块,请使用reload(),例如reload(modulename)

6.1.1。执行模块作为脚本

当你运行一个Python模块时

python fibo.py <arguments>

模块中的代码将被执行,就像您导入它一样,但__name__设置为"__main__"这意味着通过在你的模块的末尾添加这个代码:

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

您可以将该文件作为脚本以及可导入模块使用,因为仅当模块作为“主”文件执行时,才会运行解析命令行的代码:

$ python fibo.py 50
1 1 2 3 5 8 13 21 34

如果模块已导入,代码将不会运行:

>>> import fibo
>>>

这通常用于为模块提供方便的用户界面,或者用于测试目的(在脚本执行测试套件时运行模块)。

6.1.2。模块搜索路径

当名为的模块spam被导入时,解释器首先搜索具有该名称的内置模块。如果找不到,它会搜索一个名为spam.py变量给出的目录列表中的文件sys.path。 sys.path从这些位置初始化:

  • 包含输入脚本(或当前目录)的目录。
  • PYTHONPATH (目录名称列表,其语法与shell变量相同 PATH)。
  • 依赖于安装的默认值。

初始化后,Python程序可以修改sys.path包含正在运行的脚本的目录放置在搜索路径的开头,位于标准库路径之前。这意味着该目录中的脚本将被加载,而不是库目录中相同名称的模块。除非要进行替换,否则这是错误的。更多信息请参见标准模块部分 

6.1.3。“编译”Python文件

作为使用大量标准模块的短程序的启动时间的重要提速,如果spam.pycspam.py找到的目录中存在称为文件的文件,则假定这包含已经“字节编译”版本的该模块spam记录 spam.py用于创建的版本的修改时间,如果这些不匹配,则忽略文件。spam.pycspam.pyc.pyc

通常情况下,你不需要做任何事情来创建spam.pyc文件。每当spam.py成功编译时,都会尝试编写已编译的版本spam.pyc这种尝试失败并不是错误; 如果由于任何原因文件未被完全写入,则所得到的 spam.pyc文件将被识别为无效并因此被稍后忽略。spam.pyc文件的内容与平台无关,因此Python模块目录可以被不同体系结构的机器共享。

专家提示:

  • 当Python解释器与该-O标志一起被调用时,优化的代码被生成并存储在.pyo文件中。优化器目前没有多大帮助; 它只会删除assert语句。何时-O使用,所有的 字节码都被优化; .pyc文件被忽略,.py文件被编译为优化的字节码。

  • 将两个-O标志传递给Python解释器(-OO)将导致字节码编译器执行优化,在极少数情况下可能导致程序出现故障。目前只有__doc__字符串被从字节码中移除,导致更紧凑的.pyo文件。由于某些程序可能依赖于这些程序,所以如果您知道自己在做什么,则只应使用该选项。

  • 程序不运行时,它读取任何更快从.pyc或 .pyo文件时,它是从一个比读取.py文件; 这是关于更快的唯一的事情.pyc.pyo文件只是在它们加载的速度。

  • 当通过在命令行中输入脚本名称来运行脚本时,脚本的字节码永远不会写入文件.pyc.pyo文件。因此,通过将其大部分代码移动到某个模块并使用一个导入该模块的小引导脚本,可以减少脚本的启动时间。也可以直接在命令行上命名.pyc.pyo文件。

  • 对于同一个模块,可以有一个名为spam.pyc(或spam.pyo 何时-O使用)的文件spam.py而没有文件这可用于以适中难以逆向工程的形式分发Python代码库。

  • 该模块compileall可以为目录中的所有模块创建.pyc文件(或使用.pyo 时的文件-O)。

6.2。标准模块

Python带有一个标准模块库,在一个单独的文档中描述,即Python库参考(以下简称“库参考”)。一些模块被内置到解释器中; 这些提供了对操作的访问,这些操作不属于语言核心的一部分,但是为了提高效率或提供对操作系统原语(如系统调用)的访问权限。这些模块的集合是一个配置选项,它也取决于底层平台。例如,该winreg模块仅在Windows系统上提供。一个特定的模块值得注意: sys这是每个Python解释器都内置的。变量 sys.ps1sys.ps2定义用作主要和次要提示的字符串:

>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print 'Yuck!'
Yuck!
C>

这两个变量只在解释器处于交互模式时才被定义。

该变量sys.path是确定解释器的模块搜索路径的字符串列表。它被初始化为来自环境变量的默认路径PYTHONPATH,或从内置的默认if PYTHONPATH没有设置。您可以使用标准列表操作对其进行修改:

>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')

6.3。dir()功能

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

>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)  
['__displayhook__', '__doc__', '__excepthook__', '__name__', '__package__',
 '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache',
 '_current_frames', '_getframe', '_mercurial', 'api_version', 'argv',
 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats',
 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_clear', 'exc_info',
 'exc_traceback', 'exc_type', 'exc_value', 'excepthook', 'exec_prefix',
 'executable', 'exit', 'flags', 'float_info', 'float_repr_style',
 'getcheckinterval', 'getdefaultencoding', 'getdlopenflags',
 'getfilesystemencoding', 'getobjects', 'getprofile', 'getrecursionlimit',
 'getrefcount', 'getsizeof', 'gettotalrefcount', 'gettrace', 'hexversion',
 'long_info', 'maxint', 'maxsize', 'maxunicode', 'meta_path', 'modules',
 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1',
 'py3kwarning', 'setcheckinterval', 'setdlopenflags', 'setprofile',
 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout', 'subversion',
 'version', 'version_info', 'warnoptions']

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

>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir()
['__builtins__', '__name__', '__package__', 'a', 'fib', 'fibo', 'sys']

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

dir()没有列出内置函数和变量的名称。如果你想要一个列表,它们在标准模块中定义 __builtin__

>>> import __builtin__
>>> dir(__builtin__)  
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException',
 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError',
 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError',
 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning',
 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt',
 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented',
 'NotImplementedError', 'OSError', 'OverflowError',
 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError',
 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError',
 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True',
 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError',
 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError',
 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning',
 'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__',
 '__name__', '__package__', 'abs', 'all', 'any', 'apply', 'basestring',
 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr',
 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright',
 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval',
 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset',
 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input',
 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license',
 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next',
 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit',
 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round',
 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super',
 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']

6.4。软件包

包是通过使用“虚线模块名称”来构造Python模块名称空间的一种方式。例如,模块名称A.B指定名为B包的命名的子模块A就像模块的使用可以让不同模块的作者不必担心彼此的全局变量名一样,使用虚线模块名称可以让像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在搜索包子目录时搜索 sys.path目录。

__init__.py需要这些文件才能使Python将目录视为包含包; 这是为了防止具有通用名称的目录,例如string,无意中隐藏稍后在模块搜索路径上发生的有效模块。在最简单的情况下,__init__.py可以只是一个空文件,但它也可以执行包的初始化代码或设置__all__变量,稍后介绍。

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

import sound.effects.echo

这会加载子模块sound.effects.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 itemimportImportError

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

6.4.1。导入*从包

现在当用户写入时会发生什么理想情况下,人们会希望以某种方式进入文件系统,查找包中存在哪些子模块,然后将它们全部导入。这可能需要很长时间,并且导入子模块可能具有不希望的副作用,这些副作用只应在明确导入子模块时才会发生。from sound.effects import *

唯一的解决方案是软件包作者提供包的明确索引。import语句使用以下约定:如果程序包的 __init__.py代码定义了一个名为list的列表__all__,它将被视为遇到时应导入的模块名称列表当软件包的新版本发布时,软件包作者需要保持该列表为最新版本。如果软件包作者没有看到用于从包中导入*的用途,那么软件包作者也可能决定不支持它。例如,该文件可能包含以下代码:from package import *sound/effects/__init__.py

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

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

如果__all__没有定义,语句 也不会导入从包中的所有子模块到当前的命名空间; 它只确保包已被导入(可能运行任何初始化代码),然后导入包中定义的任何名称。这包括通过定义的任何名称(以及明确加载的子模块)它还包括由以前的语句显式加载的软件包的任何子模块考虑这个代码:from sound.effects import *sound.effectssound.effects__init__.py__init__.pyimport

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

在这个例子中,echosurround模块被导入到当前命名空间中,因为它们是在执行语句sound.effects中定义的from...import(这也适用于__all__定义时。)

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

请记住,使用没有任何问题实际上,这是推荐的符号,除非导入模块需要使用不同软件包中具有相同名称的子模块。from Package importspecific_submodule

6.4.2。内部包装参考

子模块通常需要彼此参照。例如,该 surround模块可能会使用该echo模块。事实上,这样的引用非常常见,因此import在查找标准模块搜索路径之前语句首先在包含的包中查找。因此,该 surround模块可以简单地使用如果在当前包(当前模块是子模块的包)中找不到导入的模块,则该 语句将查找具有给定名称的顶级模块。import echofrom echo import echofilterimport

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

从Python 2.5开始,除了上述隐式相对导入之外,您还可以使用import语句形式编写显式相对导入。这些显式相对导入使用前导点来指示相关导入中涉及的当前和父包。例如,模块中,您可以使用:from module import namesurround

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

请注意,显式和隐式相对导入都基于当前模块的名称。由于主模块的名称始终是"__main__",因此用作Python应用程序主模块的模块应始终使用绝对导入。

6.4.3。多目录中的软件包

包还支持一个更特殊的属性,__path__这被初始化为一个列表,其中包含__init__.py执行该文件中的代码之前包含该包的目录的名称这个变量可以修改; 这样做会影响将来对包中包含的模块和子包的搜索。

虽然此功能通常不是必需的,但它可用于扩展包中找到的一组模块。

脚注

[1]事实上,函数定义也是'执行'的'语句'; 模块级函数定义的执行将在模块的全局符号表中输入函数名称。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值