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

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

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

[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(modulename)

 

执行模块

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

python fibo.py <arguments>

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

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

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 的模块时,

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

如果没有找到,

spam.py 的文件。

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

  • 脚本所在的目录(或当前目录)。
  • PATH 的语法相同)。
  • 与安装相关的默认值。

sys.path

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

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

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

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

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

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

 

标准模块

Python 带有一个标准模块库,

有些模块被直接构建在解析器里;

这些操作虽然不是语言核心的部分,

但是依然被内建进来,

一方面是效率的原因,

另一方面是为了提供访问操作系统原语如系统调用的功能。

这些模块是可配置的,

也取决于底层的平台。

winreg模块只在Windows系统上提供。

sys

sys.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 模块命名空间的方式,

采用“点分模块名称”。

例如,

B 的子模块。

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

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

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

.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
              ...

导入这个包时,

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)

 item时,

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

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

比如函数、 类或者变量。

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

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

ImportError异常。

相反,

item.subitem.subsubitem 这样的语法时,

最后一项可以是一个模块或一个包,

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

 

 

 

 

从包中导入 * 

* 会发生什么?

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

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

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

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

import 语句使用以下约定:

__all__的列表,

*语句的时候,

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

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

如果包的作者认为不可以用 import * 方式导入它们的包,

也可以决定不支持它。

sound/effects/__init__.py可以包含下面的代码:

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

sound 包的三个子模块。

__all__ 没有定义,

sound.effects 包中导入所有的子模块到当前命名空间;

__init__.py 中的任何初始化代码),

然后导入包中定义的任何名称。

__init__.py 定义的任何名称(以及它显式加载的子模块)。

import 语句显式加载的子模块。

请考虑此代码:

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

from...import 语句时,

sound.effects中有定义。

__all__时也会同样工作。)

* 时只导出符合特定模式的名称,

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

记住,

specific_submodule 一点没错 !

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

6.4.2. 包内引用

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

例如,

echo 模块。

事实上,

import 语句会在标准模块搜索路径之前首先在所在的包中查找。

echofilter

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

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

sound 包),

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

echo 模块,

echo

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

 的导入形式编写显式相对导入。

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

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

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

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

 ,

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

6.4.3. 包含多个目录的包

__path__

__init__.py 所在目录的列表。

这个变量可以修改;

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

虽然通常不需要此功能,

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

脚注

[1] 模块级别的函数定义的执行将函数名放入该模块的全局符号表中。
 

相关文章: