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
View Code

这是因为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']
View Code

可以看到这是一个list。所以我们只需要把我们自定义模块的路径放入这个list python就能找到自定义模块了。

>>> sys.path.append('/tmp/python')
>>> import m1  
View Code

其实你还可以通过一个环境变量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'>}
View Code

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
View Code

可以看到我们用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
View Code

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
View Code

如上面的例子所示,我们的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()
View Code

最后有一个foo1()的调用函数语句。 load会导致这个语句被执行,如下:

>>> import m1
tihs is foo1 from m1

但是模块只在第一次import的时候被加载,以后无论import多少次都不会被加载

>>> import m1
>>> import m1
>>> import m1
>>> import m1
View Code

可以看到无论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$
View Code

然后我们用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}
View Code

要注意的是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}
View Code

正如我们看到的,globals()只返回最外层的名称空间字典。 local只返回当前调用环境的名称字典。 拿 f_middle()来举例,虽然它可以访问f_outer中的内容,但是它的globals和locals都不会包含f_outer中定义的变量。

reload函数就很简单了,reload(module)可以重新load模块一次,要注意的是使用reload的前提是模块必须被完整导入,如果你是用import from的方式导入了一些模块的属性,那么reload就不会正常工作。

 

 

 

 

 

 

 

posted on 2014-05-16 10:42  kramer  阅读(305)  评论(0编辑  收藏  举报

导航