Sivan's blog

用代码说话……
posts - 14, comments - 2, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

[学]Python用户手册笔记_3_Modules

Posted on 2010-12-20 08:54 Sivan 阅读(443) 评论(0)  编辑 收藏 引用 所属分类: Python


5. 模块 Modules

想要将程序长久保存,方便维护。Python 提供了一个方法可以从文件中获取定义,在脚本或者解释器的一个交互式实例中使用。在模块中的定义可以导入到另一个模块或主模块中。

模块是包括Python定义和声明的文件。文件名就是模块名加上“.py”后缀。模块的模块名可以由全局变量__name__得到。

# 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

保存为fibo.py到本地文件夹。

运行cmdcdfibo.py所在文件夹,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.__name__

'fibo'

>>>

如果你经常使用一个函数,你可以可以给它赋一个本地名称:

>>> fib = fibo.fib

>>> fib(10)

1

1

2

3

5

8

>>>


5.1
深入模块

模块可以像函数定义一样包含执行语句。这些语句通畅用于初始化模块。它们只在模块第一次导入时执行一次。对应于在模块中定义的所有函数的全局语义表,每一个模块都有自己的私有语义表。因此,模块作者可以在模块中使用一些全局变量,而不用担心与用户的全局变量意外冲突而引发错误。另一方面,如果你确定需要,可以像引用模块中的函数一样获取模块中的全局变量,形式modname.itemname

模块中可以导入其他模块。习惯上所有的import语句都放在模块(或脚本,等等)的开头,但这并不是必须的。被导入的模块名被放在模块的全局语义表中。

import语句的一个变体直接从被导入的模块中导入命名到本模块的语义表中。

>>> from fibo import fib, fib2

>>> 

这样不会在本地语义表中导入模块名。(上面的例子,fibo没有定义)

甚至可以导入模块中的所有定义:

>>> from fibo import *

>>> 

这样可以导入所有除了以下划线(_)开头的命名。


5.1.1
模块搜索路径

如果要导入的模块名字为spam,搜索顺序为:

1.在当前目录中搜索“spam.py”文件。

2.在环境变量PYTHONPATH代表的目录列表中搜索。

3.搜索环境PATH中的路径列表。

如果PYTHONPATH没有设置,或者文件没有找到,接下来搜索安装目录,在UNIX中,通常是“../usr/local/lib/python”。

实际上,解释器由sys.path变量指定的路径目录搜索模块,该变量初始化时默认包含了输入脚本(或当前目录),PYTHONPATH和安装目录。这样就允许Python程序了解如何修改或替换模块搜索目录。需要注意的是由于这些目录中吧哦哈uyou搜索路径中运行的脚本,所以这些脚本不应该和标准模块重名,否则Python会尝试把加载的脚本作为模块,当导入模块时。这通常会引发一个错误。


5.1.2
编译Python文件

对于引用了大量标准模块的短程,有一个提高启动速度的重要方法,如果在“spam.py”所在的目录下存在一个名为“spam.pyc”文件,它会被视为spam模块的预“编译”版本。用于创建“spam.pyc”的这一版“spam.py”的修改时间记录在“spam.pyc”文件中,如果两者不匹配,“.pyc”文件被忽略。

通常你不需要为创建“spam.pyc”文件作任何工作。一旦“spam.py”成功编译,就会试图编译对应版本的“spam.pyc”。如果有任何原因导致写入不成功,返回的“spam.pyc”文件就会视为无效,随后即被忽略。“spam.pyc”文件的内容是平台独立的,所以python模块目录可以在不同架构的机器之间共享。

部分高级技巧:

1.-O参数调用Python解释器时,会生成优化代码并保存在“.pyo”文件中。目前的优化器没有太多帮助;它只是删除了断言语句。使用-O参数时,所有的字节码都会被优化;.pyc文件被忽略,.py文件被编译为优化的字节码。

2.Python解释器传递两个-O参数会执行完全优化的二进制优化编译,这偶尔会生成错误的程序。目前的优化器,只是从二进制代码中删除了__doc__字符串,生成更为紧凑的“.pyo”文件。因为一些程序依赖这些变量的可用性,你应该只在确定无误的场合使用这一选项。

3.来自“.pyc”或“.pyo”文件中的程序不会比来自“.py”文件的运行更快;“.pyc”或“.pyo”文件只是在它们加载的时候更快一些。

4.通过脚本名在命令行运行脚本时,不会为该脚本创建的字节码代码写入“.pyc”或“.pyo”文件。如此,用一个小的启动脚本导入这个模块,就可以提高脚本的启动速度。也可以直接在命令行中指定一个“.pyc”或“.pyo”文件。

5.对于同一个模块(如spam.py),可以只有“spam.pyc”文件(或者“spam.pyo”)而没有“spam.py”文件。这样可以打包发布比较难于逆向工程的Python代码库。

6.模块可以为指定目录中的所有模块创建“.pyc”文件(或者是“.pyo”文件)。


5.2
标准模块

Python带有一个标准模块库,并发布由独立的文档,名为Python库参考手册。有一些模块内置于解释器中,这些操作的访问接口不是语言内核的一部分,但是已经内置于解释器了。这既是为了提高效率,也是为了提供操作系统原生接口,如系统调用。这类模块集合是一个依赖于底层平台的配置选项。例如,amoeba模块只提供对Amoeba原生系统的支持。有一个具体的模块值得注意:sys,这个模块内置于所有的Python解释器。变量sys.ps1sys.ps2定义了主提示符和副提示符字符串:

>>> import sys

>>> sys.ps1

'>>> '

>>> sys.ps2

'... '

>>>

这两个变量只在解释器的交互模式下有意义。

变量sys.path是解释器模块搜索路径的字符串列表。它由环境变量PYTHONPATH初始化,如果没有设定PYTHONPATH,就由内置的默认值初始化。可以用标准的字符串操作修改它:


5.3 dir()
函数

内置函数dir()用于按模块名搜索模块定义,它返回一个字符串类型的存储列表:

>>> import fibo, sys

>>> dir(fibo)

['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'fib', 'fib2']

>>> dir(sys)

['__displayhook__', '__doc__', '__excepthook__', '__name__', '__package__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_getframe', 'api_version', 'appargv', 'appargvoffset', 'argv', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_clear', 'exc_info', 'exc_type', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'getcheckinterval', 'getdefaultencoding', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'gettrace', 'getwindowsversion', 'hexversion', 'maxint', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'py3kwarning', 'setcheckinterval', 'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version', 'version_info', 'warnoptions', 'winver']

>>>

无参数调用时,dir()函数返回当前定义的命名:

>>> a = [1, 2, 3, 4, 5]

>>> import fibo

>>> fib = fibo.fib

>>> dir()

['__builtins__', '__doc__', '__name__', '__package__', 'a', 'fib', 'fibo', 'pywin', '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', 'WindowsError', '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', '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']

>>>


5.4

包通常是使用用“圆点模块名”的结构化模块命名空间。例如,名为A.B的模块表示,名为“A”的包中名为“B”的子模块。正如同用模块来保存不同的模块架构可以避免全局变量之间的相互冲突,使用圆点模块名保存箱NumPyPython Imaging Library之类的不同类库架构可以避免模块之间的命名冲突。

假设你现在想要设计一个模块集(一个“包”)来统一处理声音文件和声音数据。存在几种不同的声音格式,于是,为了在不同类型的文件格式之间转换,需要维护一个不断增长的包集合。可能你还想要对声音数据做很多不同的操作,所以你要加入一个无线留模块来执行这些操作。你的包可能会是这个样子(通过分级的文集体系来进行分组)。

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

                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 item方式导入包时,这个子项既可以是包中的衣柜子模块,也可以是包中定义的其他命名,像函数、类或变量。import语句首先核对是否包中有这个子项,如果没有,它假定这是一个模块,并尝试加载它。如果没有找到它,会引发一个ImportError异常。

相反,使用类似import item.subitem.subsubitem这样的语法时,这些子项必须是包,最后的子项可以是包或模块,但不能是前面子项中定义的类、函数或变量。


5.4.1 import * from a package

那么当用户写下from Sound.Effects import * 时会发生什么事?理想中,总是希望再文件系统中找出包中所有的子模块,然后导入它们。不幸的是,这个操作在MacWindows平台上工作的并不太好,这些文件系统的文件大小写并不敏感!在这些平台上没有什么方法可以确保一个叫“ECHO.PY”的文件应该导入为模块echoEchoECHO

对于包的作者来说唯一的解决方案就是给提供一个明确的包索引。import语句按如下条件进行转换:执行form package import *时,如果包中的“__init__.py”代码定义了一个名为__all__的链表,就会按照链表中给出的模块名进行导入。新版本包发布时作者可以任意更新这个链表。如果包作者不想import*的时候导入他们的包中所有模块,那么也可能会决定不支持它(import*)例如,“Sounds/Effects/__init__.py”这个文件可能包括如下代码:

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

这意味着from Sound.Effects import * 语句会从Sound包中导入以上三个已命名的子模块。

如果没有定义__all__from Sound.Effects import *语句不会从Sound.Effects包中导入所有的子模块到当前命名空间。Effects导入到当前的命名空间,只能确定的是导入了Sound.Effects包(可能会运行“__init__.py”中的初始化代码)以及在包中定义的所有命名。这些包含任何通过“__init__.py”定义的命名(和明确导入的子模块)。同业也包括了前述的import语句从包中明确导入的子模块。看下面的代码:

import sound.effects.echo

import sound.effects.surround

from sound.effects import *

在这个例子中,echosurround模块导入了当前的命名空间,这是因为执行fromimport语句时他们已经被定义在Sound.Effects包中(定义了__all__时也会同样工作)。

需要注意的是习惯上不主张从一个包货模块中用import*导入所有模块,因为这样通常意味着可读性会很差。然而,在交互会话中,这做可以减少输入,certain modules are designed to export only names that follow certain patterns

记住,from package import specific_submodule没哟错误!事实上,除非导入的模块需要使用其他包中的同名子模块,否则这是推荐写法。


5.4.2
内部包

子模块之间需要互相引用。例如,surround模块可能会引用echo模块。事实上,这样的引用如此普遍,以至于import语句会先搜索包内部,然后才是标准模块搜索路径。因此surround模块可以简单的调用import echo或者from echo import echofilter。如果没有在当前的包中发现要导入的模块,import语句会依据指定名寻找一个顶级模块。

如果包使用了子包结构(就像示例中的Sound包),不存在什么从邻近的包中引用子模块的便捷方式--必须使用子包的全名。例如,如果Sound.Filters.vocoder包需要使用Sound.Effects包中的echosa模块,它可以使用from Sound.Effects import echo

(下面的是2.6中的内容)

Python2.5,加入了上述的隐含相对包含,你可以使用form module import name形式的引入语句来写显示的相对包含。这些显示的相对包含使用点号来指出当前和父包参与到相对包含中。以surround模块为例,你可以使用

from . import echo

from .. import formats

from ..filters import equalizer

注意显示和隐式包含基于当前模块的名字。因此主模块的名字通常是“__main__”,Python程序中的主模块应当总是使用绝对路径包含。


5.4.3
多重路径中的包

包支持一个更为特殊的变量,__path__。在包的“__init__.py”文件代码执行之前,该变量初始化一个目录名列表。该变量可以修改,它作用域包中的子包和模块的搜索功能。

这个功能可以用于扩展包中的模块集,不过它不常用。


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理