python 模块
1 什么是模块
模块支持从逻辑上组织 Python 代码。 当代码量变得相当大的时候, 我们最好把代码分成一些有组织的代码段,这样便于管理代码,而且可以实现代码重用。
1.1 模块和文件
模块是按照逻辑来组织python 代码的方法,而文件是物理层面上组织python模块的方法。一个文件可以看成是一个独立的模块。一个模块也要被放在一个文件里。
1.2 模块搜索路径
在使用import 来导入模块的时候可能会遇到下面的错误
>>> import m1 Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: No module named m1
这是因为python找不到你定义的模块。python在寻找模块的时候是有自己的寻找路径的。进入python,import sys 然后输入 sys.path你就可以看到这个寻找路径:
>>> import sys >>> sys.path ['', '/usr/local/lib/python25.zip', '/usr/local/lib/python2.5', '/usr/local/lib/python2.5/plat-sunos5', '/usr/local/lib/python2.5/lib-tk', '/usr/local/lib/python2.5/lib-dynload', '/usr/local/lib/python2.5/site-packages']
可以看到这是一个list。所以我们只需要把我们自定义模块的路径放入这个list python就能找到自定义模块了。
>>> sys.path.append('/tmp/python') >>> import m1
其实你还可以通过一个环境变量PYTHONPATH来控制这个sys.path list。 比如,下面的实验:
我们可以看到最开始这个变量并没有设置:
topdev[/export/home/oratop ] echo $PYTHONPATH topdev[/export/home/oratop ]
下面我们设置这个变量,让它包含几个我们制定的路径,路径间用冒号做分隔符
topdev[/export/home/oratop ] export PYTHONPATH=/path1:/path2
topdev[/export/home/oratop ]
然后我们再打开python看一下sys.path
>>> import sys >>> sys.path ['', '/path1', '/path2', '/usr/local/lib/python25.zip', '/usr/local/lib/python2.5', '/usr/local/lib/python2.5/plat-sunos5', '/usr/local/lib/python2.5/lib-tk', '/usr/local/lib/python2.5/lib-dynload', '/usr/local/lib/python2.5/site-packages']
OK。 可以发现sys.path是可以用这个PYTHONPATH环境变量来控制的。
我们不但可以控制python去哪查找我们的module,我们还可以查看python中当前导入的module都是来自哪里,办法就是查看sys.module。这将返回一个字典。该字典的key是模块名,value是模块位置
>>> sys.modules {'copy_reg': <module 'copy_reg' from '/usr/local/lib/python2.5/copy_reg.py'>, '__main__': <module '__main__' (built-in)>, 'site': <module 'site' from '/usr/local/lib/python2.5/site.py'>, '__builtin__': <module '__builtin__' (built-in)>, 'encodings': <module 'encodings' from '/usr/local/lib/python2.5/encodings/__init__.py'>, 'encodings.encodings': None, 'posixpath': <module 'posixpath' from '/usr/local/lib/python2.5/posixpath.py'>, 'encodings.codecs': None, 'os.path': <module 'posixpath' from '/usr/local/lib/python2.5/posixpath.py'>, '_codecs': <module '_codecs' (built-in)>, 'stat': <module 'stat' from '/usr/local/lib/python2.5/stat.py'>, 'zipimport': <module 'zipimport' (built-in)>, 'warnings': <module 'warnings' from '/usr/local/lib/python2.5/warnings.py'>, 'encodings.types': None, 'UserDict': <module 'UserDict' from '/usr/local/lib/python2.5/UserDict.py'>, 'encodings.ascii': <module 'encodings.ascii' from '/usr/local/lib/python2.5/encodings/ascii.py'>, 'sys': <module 'sys' (built-in)>, 'codecs': <module 'codecs' from '/usr/local/lib/python2.5/codecs.py'>, 'types': <module 'types' from '/usr/local/lib/python2.5/types.py'>, '_types': <module '_types' (built-in)>, 'signal': <module 'signal' (built-in)>, 'linecache': <module 'linecache' from '/usr/local/lib/python2.5/linecache.py'>, 'posix': <module 'posix' (built-in)>, 'encodings.aliases': <module 'encodings.aliases' from '/usr/local/lib/python2.5/encodings/aliases.py'>, 'exceptions': <module 'exceptions' (built-in)>, 'os': <module 'os' from '/usr/local/lib/python2.5/os.py'>}
2 导入模块
2.1 from import语句
我们知道可以用import语句导入模块,但有时候你可能只想使用模块中的一两个属性,这样如果把整个模块全部导入反而会耗费资源。我们可以用from import来实现这一点。 from module import attribute是指从某个模块导入某个属性的意思。
topdev[/tmp/python ] cat m1.py def foo1(): print 'tihs is foo1 from m1' att1='first' att2='second' topdev[/tmp/python ] python Python 2.5 (r25:51908, Sep 20 2006, 06:18:53) [GCC 3.4.6] on sunos5 Type "help", "copyright", "credits" or "license" for more information. >>> >>> from m1 import att1 >>> att1 'first' >>> att2 Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'att2' is not defined
可以看到我们用from m1 import att1只导入了att1属性,所以也只有访问att1属性好使。 另一点要注意的是,from import的形式是把属性导入到了当前的名字空间中去,你不需要用句点标示符 如 m1.att1来访问属性att1 。 只需要att1。
2.2 import的作用域
如果你是在全局import模块,那么模块在全局都可以访问,如果是在局部import,那么模块也只能在局部访问。
>>> import m1 >>> m1.att1 'first' >>> ^D topdev[/tmp/python ] python Python 2.5 (r25:51908, Sep 20 2006, 06:18:53) [GCC 3.4.6] on sunos5 Type "help", "copyright", "credits" or "license" for more information. >>> >>> def foo(): ... import m1 ... print m1.att2 ... >>> foo() second >>> m1.att2 Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'm1' is not defined
2.3 扩展的import
有时候你在import一个模块后,想为它改个名字,你就可以用import as。 具体情况下面代码
topdev[/tmp/python ] cat m1.py def foo1(): print 'tihs is foo1 from m1' att1='first' att2='second' topdev[/tmp/python ] topdev[/tmp/python ] python Python 2.5 (r25:51908, Sep 20 2006, 06:18:53) [GCC 3.4.6] on sunos5 Type "help", "copyright", "credits" or "license" for more information. >>> >>> import m1 as m2 >>> m2.att1 'first' >>> m1.att1 Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'm1' is not defined
如上面的例子所示,我们的m1模块有att1 att2 foo1 这几个属性。在用import as 改名为m2后,我们在python里面就得用m2来访问这个模块了。
2.4 导入imort 和 加载 load
import 模块后 模块会被load到python中。load会导致代码被执行,比如下面的模块:
topdev[/tmp/python ] cat m1.py def foo1(): print 'tihs is foo1 from m1' att1='first' att2='second' foo1()
最后有一个foo1()的调用函数语句。 load会导致这个语句被执行,如下:
>>> import m1 tihs is foo1 from m1
但是模块只在第一次import的时候被加载,以后无论import多少次都不会被加载
>>> import m1 >>> import m1 >>> import m1 >>> import m1
可以看到无论import多少次,foo1()都没有被执行。
2.5 import 属性作用域的问题
看一下下面的例子,首先我们有一个模块 importee 如下,里面有attr=123 和 foo这两个属性
bash-2.05$ cat importee.py attr=123 def foo(): print 'attr in importee is', attr bash-2.05$
然后我们用from import语句如下:
>>> from importee import attr,foo
这样 attr 和 foo就变成当前名称空间里的属性了。然后我们在当前的名称空间里为attr重新赋值
>>> attr='abc'
现在在当前的名称空间里attr变成了abc。但是你认为运行foo会是什么样?
>>> foo() attr in importee is 123
仍然是123。 所以你在全局名称空间里做的attr=abc其实只是在当前名称空间里新创建了一个变量attr='abc',没有改变importee里面的attr。 其实还有一个疑问就是,我们知道python的函数是在运行时刻才去找变量值的。那么现在全局的attr是abc了,为什么foo找到的不是它呢? 这是因为foo在运行时刻找的是importee里面的attr。 不信看下面的代码
>>> import importee >>> importee.attr=2 >>> foo() attr in importee is 2
2.6 globals() locals()和 reload函数
globals()返回当前调用者的 global名称空间的字典,locals()返回调用者local名称空间的字典。如下:
>>> v1=1 >>> v2=2 >>> >>> def foo(): ... l1=1 ... l2=2 ... print 'globals() is ', globals() ... print 'locals() is ', locals() ... >>> foo() globals() is {'__builtins__': <module '__builtin__' (built-in)>, 'v1': 1, 'v2': 2, '__name__': '__main__', 'foo': <function foo at 0x1ebeb0>, '__doc__': None} locals() is {'l2': 2, 'l1': 1}
要注意的是global 和 local 是两个很明确的概念,就是当前运行环境的最外层和最内层,至于中间的名称空间,这两个函数不会返回的,比如:
>>> g1=1 >>> def f_outer(): ... outer=11 ... print 'globals in f_outer ', globals() ... print 'locals in f_outer ', locals() ... def f_middle(): ... middle=111 ... print 'globals in f_middle', globals() ... print 'locals in f_middle', locals() ... def f_inner(): ... inner=1111 ... print 'globals in f_inner ', globals() ... print 'locals in f_inner ', locals() ... f_inner() ... f_middle() ... >>> >>> >>> >>> >>> f_outer() globals in f_outer {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, 'g1': 1, 'f_outer': <function f_outer at 0x1cfc30>} locals in f_outer {'outer': 11} globals in f_middle {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, 'g1': 1, 'f_outer': <function f_outer at 0x1cfc30>} locals in f_middle {'middle': 111} globals in f_inner {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, 'g1': 1, 'f_outer': <function f_outer at 0x1cfc30>} locals in f_inner {'inner': 1111}
正如我们看到的,globals()只返回最外层的名称空间字典。 local只返回当前调用环境的名称字典。 拿 f_middle()来举例,虽然它可以访问f_outer中的内容,但是它的globals和locals都不会包含f_outer中定义的变量。
reload函数就很简单了,reload(module)可以重新load模块一次,要注意的是使用reload的前提是模块必须被完整导入,如果你是用import from的方式导入了一些模块的属性,那么reload就不会正常工作。