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.ps1和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 模块命名空间的方式,
采用“点分模块名称”。
例如,
模块名 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] | 实际上,函数的定义也是‘执行过’的‘语句’;模块级别的函数定义的执行将函数名放入该模块的全局符号表中。 |
python 深入模块和包的更多相关文章
- Python之模块和包导入
Python之模块和包导入 模块导入: 1.创建名称空间,用来存放模块XX.py中定义的名字 2.基于创建的名称空间来执行XX.py. 3.创建名字XX.py指向该名称空间,XX.名字的操作,都是以X ...
- 一文搞懂 Python 的模块和包,在实战中的最佳实践
最近公司有个项目,我需要写个小爬虫,将爬取到的数据进行统计分析.首先确定用 Python 写,其次不想用 Scrapy,因为要爬取的数据量和频率都不高,没必要上爬虫框架.于是,就自己搭了一个项目,通过 ...
- (Python )模块、包
本节开始学习模块的相关知识,主要包括模块的编译,模块的搜索路径.包等知识 1.模块 如果我们直接在解释器中编写python,当我们关掉解释器后,再进去.我们之前编写的代码都丢失了.因此,我们需要将我们 ...
- Python 基金会 —— 模块和包简介
一.模块(Module) 1.模块的作用 在交互模式下输出的变量和函数定义,一旦终端重新启动后,这些定义就都不存在了,为了持久保存这些变量.函数等的定义,Python中引入了模块(Modul ...
- python基础-------模块与包(一)
模块与包 Python中的py文件我们拿来调用的为之模块:主要有内置模块(Python解释器自带),第三方模块(别的开发者开发的),自定义模块. 目前我们学习的是内置模块与第三方模块. 通过impor ...
- python中模块,包,库的概念
模块:就是.py文件,里面定义了一些函数和变量,需要的时候就可以导入这些模块. 包:在模块之上的概念,为了方便管理而将文件进行打包.包目录下第一个文件便是 __init__.py,然后是一些模块文件和 ...
- python的模块与包的导入
类似于C语言的包含头文件去引用其他文件的函数,python也有类似的机制,常用的引入方法有以下 import 模块名 #模块名就是py文件名 #使用这种方法以后调用函数的时候要使用模块名.函数名()这 ...
- day21 python之模块和包
一 模块 1 什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用python编 ...
- python之模块与包
一模块 二包 一模块 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用python编写的代 ...
随机推荐
- IIS------IIS上部署MVC网站,打开后ExtensionlessUrlHandler-Integrated-4.0解决办法
链接: http://www.cnblogs.com/mrma/p/3529859.html
- photobooth.js jquery
<div id="example" class="photobooth" style="width:758px;height:400px&quo ...
- ubuntu-E:Encountered a section with no Package: header的解决办法 (转)
E:Encountered a section with no Package: header, E:Problem with MergeList /var/lib/apt/lists/cn.arch ...
- ASP.NET WebAPI 08 Message,HttpConfiguration,DependencyResolver
ASP.NET WebAPI 08 Message,HttpConfiguration,DependencyResolver Message WebAPI作为通信架构必定包含包含请求与响应两个方法 ...
- python中os/sys/platform模块区别
os:This module provides a portable way of using operating system dependent functionality. sys:This m ...
- jQuery中的.bind()、.live()和.delegate()之间区别分析
jQuery中的.bind()..live()和.delegate()之间区别分析,学习jquery的朋友可以参考下. DOM树 首先,可视化一个HMTL文档的DOM树是很有帮助的.一个简单的 ...
- 关于MySQL的SLEEP(N)函数
都知道通过在MySQL中执行select sleep(N)可以让此语句运行N秒钟: ? 1 2 3 4 5 6 7 mysql> select sleep(1); +----------+ | ...
- Method Swizzling (方法调配)
Method Swizzling是改变一个selector的实际实现的技术.通过这一技术,我们可以在运行时通过修改类的分发表中selector对应的函数,来修改方法的实现. 例如,我们想跟踪在程序中每 ...
- [工具]Swagger-api接口文档描述
摘要 工作中经常的用到webapi,之前都是提供的使用postman模拟请求的截图,非常的不方便,如果能在项目中集成一个在线查看接口说明的地方,肯定更方便更直观.在网上看到swagger这个组件,界面 ...
- 代码中access 的使用
C++代码:if(access(strZip.c_str(), 0) == 0){...} 此处为判断strZip中文件是否存在 .c_str() 是他自身字符串名称,该名称是一个压缩文件 ...