python 深入模块和包

模块可以包含可执行语句以及函数的定义。

这些语句通常用于初始化模块。

它们只在 第一次 导入时执行。只在第一次导入的时候执行,第一次。妈蛋的第一次。。。后面再次导入就不执行了。

[1](如果文件以脚本的方式执行,它们也会运行。)

每个模块都有自己的私有符号表,

模块内定义的所有函数用其作为全局符号表。

被导入的模块的名字放在导入模块的全局符号表中。

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

这种方式不会导入以下划线 (_) 开头的名称。

注意一般情况下不赞成从一个模块或包中导入 * 

因为这通常会导致代码很难读。

不过,在交互式会话中这样用是可以的,它可以让你少敲一些代码。

注意

出于性能考虑,每个模块在每个解释器会话中只导入一遍。

因此,如果你修改了你的模块,你必需重新启动解释器 —— 或者,

如果你就是想交互式的测试这么一个模块,

可以使用reload(),例如reload(modulename)

执行模块

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

python fibo.py <arguments>

模块中的代码将会被执行,就像导入它一样,

不过此时 __name__ 被设置为 "__main__" 

也就是说,如果你在模块后加入如下代码:

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

就可以让此文件既可以作为可执行的脚本,

也可以当作可以导入的模块,

因为解析命令行的那部分代码只有在模块作为 “main” 文件执行时才被调用:

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

如果模块是被导入的,

将不会运行这段代码:

>>>

>>> import fibo
>>>

这种方法通常用来为模块提供一个方便的用户接口,

或者用来测试(例如直接运行脚本会执行一组测试用例)。

模块搜索路径

当导入一个名为 spam 的模块时,

解释器首先搜索具有该名称的内置模块。

如果没有找到,

它会接着到 sys.path 变量给出的目录中查找名为 spam.py 的文件。

sys.path变量的初始值来自这些位置:

  • 脚本所在的目录(或当前目录)。
  • PYTHONPATH (一个包含目录名的列表,与 shell 变量PATH 的语法相同)。
  • 与安装相关的默认值。

初始化后,Python 程序可以修改sys.path

脚本所在的目录被放置在搜索路径的最开始,

也就是在标准库的路径之前。

这意味着将会加载当前目录中的脚本,

库目录中具有相同名称的模块不会被加载。

除非你是有意想替换标准库,

否则这应该被当成是一个错误。

标准模块

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

如果 PYTHONPATH 未设置则来自于内置的默认值。

你可以使用标准的列表操作修改它:

>>>

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

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‘]

包是一种管理 Python 模块命名空间的方式,

采用“点分模块名称”。

例如,

模块名 A.B 表示包A 中一个名为 B 的子模块。

就像模块的使用让不同模块的作者不用担心相互间的全局变量名称一样,

点分模块的使用让包含多个模块的包(例如 Numpy 和 Python Imaging Library)的作者也不用担心相互之间的模块重名。

假设你想要设计一系列模块(或一个“包”)来统一处理声音文件和声音数据。

现存很多种不同的声音文件格式 (通常由它们的扩展名来识别,例如: .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 中的目录以寻找这个包的子目录。

为了让 Python 将目录当做包,

目录下必须包含 __init__.py 文件;

这样做是为了防止一个具有常见名字(例如 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 item时,

item 可以是包的子模块(或子包),

也可以是包中定义的一些其它的名称,

比如函数、 类或者变量。

import语句首先测试 item 在包中是否有定义;

如果没有,它假定它是一个模块,并尝试加载它。

如果未能找到,则引发ImportError异常。

相反,

使用类似 import item.subitem.subsubitem 这样的语法时,

除了最后一项其它每项必须是一个包;最后一项可以是一个模块或一个包,

但不能是在前一个项目中定义的类、函数或变量。

从包中导入 *

那么现在如果用户写成 from sound.effects import * 会发生什么?

理想情况下,他应该是希望到文件系统中寻找包里面有哪些子模块,并把它们全部导入进来。

这可能需要很长时间,而且导入子模块可能会产生想不到的副作用,

这些作用本应该只有当子模块是显式导入时才会发生。

唯一的解决办法是包的作者为包提供显式的索引。

import 语句使用以下约定:

如果包中的 __init__.py 代码定义了一个名为__all__的列表,

那么在遇到 from package import *语句的时候,

应该把这个列表中的所有模块名字导入。

当包有新版本包发布时,就需要包的作者更新这个列表了。

如果包的作者认为不可以用 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 *

在这个例子中,执行 from...import 语句时,

echo 和 surround 模块被导入到当前命名空间是因为它们在sound.effects中有定义。

(定义了 __all__时也会同样工作。)

虽然某些模块设计成使用 import * 时只导出符合特定模式的名称,

在产品代码中使用这种写法仍然是不好的做法。

记住,

使用 from Package import specific_submodule 一点没错 !

事实上,这是推荐的写法,除非导入的模块需要使用其它包中的同名子模块。

6.4.2. 包内引用

子模块通常需要相互引用。

例如,

surround 模块可能会使用 echo 模块。

事实上,

这种引用是如此常见以致 import 语句会在标准模块搜索路径之前首先在所在的包中查找。

因此,surround 模块可以简单地使用import echo 或 from echo import echofilter

如果在当前包(当前模块属于其子模块的包)中未找到要导入的模块,

import 语句会查找具有给定名称的顶级模块。

如果一个包是子包(比如例子中的 sound 包),

你可以使用绝对导入来引用兄弟包的子模块。

例如,如果模块 sound.filters.vocoder 需要使用sound.effects 包中的 echo 模块,

它可以使用 from sound.effects import echo

Python 2.5 开始,除了上面描述的隐式相对导入,

你可以使用from module import name 的导入形式编写显式相对导入。

这些显式的相对导入使用前导的点号表示相对导入的是从当前包还是上级的包。

以 surround 模块为例,你可以使用:

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

注意,显式和隐式相对导入都基于当前模块的名称。

因为主模块的名字总是 "__main__" ,

Python 应用程序的主模块应该总是用绝对导入。

6.4.3. 包含多个目录的包

包还支持一个特殊的属性, __path__

在文件运行之前,该变量被初始化为一个包含 __init__.py 所在目录的列表。

这个变量可以修改;

这样做会影响未来包中包含的模块和子包的搜索。

虽然通常不需要此功能,

它可以用于扩展包中的模块的集合。

脚注

[1] 实际上,函数的定义也是‘执行过’的‘语句’;模块级别的函数定义的执行将函数名放入该模块的全局符号表中。
时间: 2024-10-05 04:58:44

python 深入模块和包的相关文章

Python的模块与包如何使用?

本文和大家分享的主要是python模块与包相关内容,一起来看看吧,希望对大家学习python有所帮助. 一.Python 模块简介 在开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式.在 Python 中,一个 .py 文件就称之为一个模块(Module). 之前我们学习过函数,知道函数是实现一项或多项功能的一段程序 .其实模

python之模块与包

一模块 二包 一模块 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用python编写的代码(.py文件) 2 已被编译为共享库或DLL的C或C++扩展 3 包好一组模块的包 4 使用C编写并链接到python解释器的内置模块 为什么要使用模块 如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过pyt

selenium + python自动化测试unittest框架学习(四)python导入模块及包知识点

在写脚本的时候,发现导入某些模块,经常报错提示导入模块失败,这里来恶补下python导入模块的知识点. 1.模块导入时文件查找顺序 在脚本中,import xxx模块时的具体步骤: (1)新建一个module (2)将module插入到sys.module (3)查找module的路径,查找的顺序为先查找当前使用导入模块的文件同一级目录,之后是python的搜索模块的路径集sys.path,最后是python所添加的默认环境变量的路径Python path (4)module查找到之后装载mod

python基础---模块与包

1.模块导入方法 常见的场景: 一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀,导入模块可以实现功能的重复利用 import加载的模块分为四个通用类别: 1 使用python编写的代码(.py文件) 2 已被编译为共享库或DLL的C或C++扩展 3 包好一组模块的包 4 使用C编写并链接到python解释器的内置模块 a. import语句 python 内置了很多模块,比如os.sys.time等,也可以是自定义模块.模块包.C扩展等,使用import无

Python之模块和包学习

模块简介 python是由一系列的模块组成的,每个模块就是一个py为后缀的文件,同时模块也是一个命名空间,从而避免了变量名称冲突的问题.模块我们就可以理解为lib库,如果需要使用某个模块中的函数或对象,则要导入这个模块才可以使用,除了系统默认的模块(内置函数)不需要导入外. 导入直接使用如下语法:  import 模块名称 (不要.py后缀) 这样导入成功后,就可以在另外一个模块中使用被导入模块的功能函数或对象. 举例如下,比如在F:\Pro-files\workspace\myPython目录

Python学习---模块和包

模块: 一个模块就是一个包含Python代码的文件,一个文件就是一个模块 为什么使用模块 1.现在程序开发文件比较大,都放在一个文件中维护不方便,拆分成多个文件方便维护和管理 2.模块可以增加代码的重用率 3.模块可以当做命名空间 如何定义自己的模块 模块本身就是一个文件,所有py代码都可以在文件中直接书写,不过我们开发公用模块时,最好在模块中书写一下内容 变量 模块中的属性 函数 单独的功能 类 相似功能组合 模块测试代码 临时使用,被导入时不会执行 测试代码: 测试代码经常在开发模块时用于测

PYTHON常用模块和包

模块 '''模块:一系列功能的集合体?常见的四种模块:1.使用python编写的.py文件2.把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)3.使用C编写并链接到python解释器的内置模块4.已被编译为共享库或DLL的C或C++扩展''' 模块的搜索路径 '''搜索顺序:内存 => 内置模块 => sys.path?1.导入模块会优先在内存中查找2.内存中没有被加载的话,再去查找内置模块3.还没有查找到,就根据sys.path中的路径顺序逐一

第一篇:python的模块与包

模块的简介 模块就是一组功能的集合体,我们的程序可以导入模块来复用模块里的功能.每一个 Python 脚本.py文件都可以被当成是一个模块.模块以磁盘文件的形式存在.当一个模块变得过大,并且驱动了太多功能的话,就应该考虑拆一些代码出来另外建一个模块.模块里的代码可以是一段直接执行的脚本,也可以是一堆类似库函数的代码,从而可以被别的模块导 入(import)调用.模块可以包含直接运行的代码块.类定义. 函数定义或这几者的组合. 模块分类:Python标准库模块.Python第三方模块.应用程序自定

Python从零开始——模块与包

一:Python模块知识概览 二:Python模块的定义与引入 三:模块的搜素与命名空间 四:深入模块 五:模块管理——包的定义与引入 原文地址:https://www.cnblogs.com/ygj0930/p/11001315.html