首页 > 代码库 > python 模块

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就不会正常工作。