模块是程序

以.py为后缀
解释器会自动在一些目录下查找模块
但我们也可以自行指定一些目录

In [1]:
import sys
In [3]:
sys.path.append('/home/zk/桌面/chap10 自带电池/')
#把路径字符串加入(append)到sys.path中
#字符串中不能直接写成‘~/桌面/chap10 自带电池'
In [4]:
import hello
#我们已经在目录下写了一个模块hello.py
hello, world!

hello.py内容:
print 'hello, world!'

导入模块的时候,会在同一目录下会产生一个.pyc的文件
该文件是经过处理的,能使python能更加有效地处理的文件
稍后如果导入同一模块,纳闷导入的是.pyc而不是.py
除非.py文件改变,此时会产生新的.pyc

In [6]:
#如果再次导入这个模块,它的语句不会被重新调用
import hello
In [7]:
#看,不再打印出“hello, world!”了

为什么只导入一次呢?
试想,如果有两个模块A和B,
A模块里面导入了B模块,B模块又导入了A模块,
如果不限制导入次数,那不就陷入死循环了么?

In [8]:
#如果非要重新载入呢?我们可以借助reload函数(python3中已不存在这个函数)
hello = reload(hello)
hello, world!

In [9]:
hello
Out[9]:
<module 'hello' from '/home/zk/桌面/chap10 自带电池/hello.pyc'>

模块用于定义

模块的重要之处在于保持了作用域,所以模块用于定义,而不用于打印之类的语句
通常定义的是类、函数、特殊的变量等
模块的作用:防止代码重用、增加测试代码
防止代码重用容易理解,下面说明以下测试代码

In [14]:
import hello2
In [15]:
hello2.test()
hello, world!

hello2.py内容
def hello():
print 'hello, world!'
def test():
hello()
if __name__ == '__main__':test()

这里的__name__变量的内容是告知当前运行的程序,如果是主程序那就是__main__,如果是模块那就是对应的模块名

使模块可用

有两种方法——放到指定目录下、给解释器指定路径

放到指定目录下

In [17]:
import sys, pprint
In [19]:
pprint.pprint(sys.path)
#这些搜索路径以字符串的形式保存在列表里,通过sys.path访问     
#如果数据结构过大,不能一次打完,可以借助pprint模块的pprint函数更加智能的打印
['',
 '/usr/lib/python2.7',
 '/usr/lib/python2.7/plat-x86_64-linux-gnu',
 '/usr/lib/python2.7/lib-tk',
 '/usr/lib/python2.7/lib-old',
 '/usr/lib/python2.7/lib-dynload',
 '/usr/local/lib/python2.7/dist-packages',
 '/usr/lib/python2.7/dist-packages',
 '/usr/lib/python2.7/dist-packages/PILcompat',
 '/usr/lib/python2.7/dist-packages/gtk-2.0',
 '/usr/lib/pymodules/python2.7',
 '/usr/lib/python2.7/dist-packages/ubuntu-sso-client',
 '/usr/lib/python2.7/dist-packages/IPython/extensions',
 '/home/\xe6\xa1\x8c\xe9\x9d\xa2/chap10 \xe8\x87\xaa\xe5\xb8\xa6\xe7\x94\xb5\xe6\xb1\xa0/',
 '/home/zk/\xe6\xa1\x8c\xe9\x9d\xa2/chap10 \xe8\x87\xaa\xe5\xb8\xa6\xe7\x94\xb5\xe6\xb1\xa0/']

In [20]:
#解释器搜索路径很多,我们一般是把模块存储到python/lib/site-packages目录中

给解释器指定路径

  • 把模块放置到指定目录有不适用的情况
    • 不希望自己的模块填满解释器的目录
    • 不具有解释器目录的存储文件权限
    • 想将模块放在其他地方
  • 一种方法是把搜索路径加入到sys.path列表中
  • 还有一种方法是设置PYTHONPATH环境变量
    • 在UNIX下
      设置.bashrc文件,加入如下命令把~/python目录加入搜索路径:
      export PYTHONPATH=$PYTHONPATH:~/python
    • 在Windows下
      • 控制面板--系统--高级--环境变量--用户变量,选中PYTHONPATH变量,点击编辑,加入新的搜索路径(多个目录用冒号:隔开)
      • 也可以编辑C盘根目录下的autoexec.bat文件,增加一行设置“set PYTHONPATH=%PYTHONPATH%;C:\python”
      • 有的IDE可能有自身的机制

包(package)

为了组织好模块,我们可以将他们分组成包
模块所在目录加入一个__init__.py模块,即可将目录作为包目录,而该模块称为包代码
这样以来,目录下的所有模块就组成了一个包

假设我们创建了一个目录drawing,目录下有__init__.py、colors.py、shapes.py三个模块

In [21]:
#导入包
#——import 包
import drawing
In [22]:
#导入包内的某个模块——法1
#——import 包.模块
import drawing.colors
In [23]:
#导入包内的某个模块——法2
#——from 包 import 模块
from drawing import shapes

探究模块内容

dir函数查看模块内容

使用前模块必须被导入

In [25]:
dir(copy)      #不导入模块会出错
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-25-93eb92fceecb> in <module>()
----> 1 dir(copy)      #不导入模块会出错

NameError: name 'copy' is not defined
In [26]:
import copy
In [27]:
dir(copy)
Out[27]:
['Error',
 'PyStringMap',
 '_EmptyClass',
 '__all__',
 '__builtins__',
 '__doc__',
 '__file__',
 '__name__',
 '__package__',
 '_copy_dispatch',
 '_copy_immutable',
 '_copy_inst',
 '_copy_with_constructor',
 '_copy_with_copy_method',
 '_deepcopy_atomic',
 '_deepcopy_dict',
 '_deepcopy_dispatch',
 '_deepcopy_inst',
 '_deepcopy_list',
 '_deepcopy_method',
 '_deepcopy_tuple',
 '_keep_alive',
 '_reconstruct',
 '_test',
 'copy',
 'deepcopy',
 'dispatch_table',
 'error',
 'name',
 't',
 'weakref']
In [29]:
#函数内容有很多下划线开头的名字,这些名字约定俗成地不为外部使用而准备,所以我们不用关注他们(借助字符串的startswith方法)
[n for n in dir(copy) if not n.startswith('_')]
Out[29]:
['Error',
 'PyStringMap',
 'copy',
 'deepcopy',
 'dispatch_table',
 'error',
 'name',
 't',
 'weakref']

__all__变量

这个变量存在于模块中,以列表的形式告诉我们有哪些公共接口(pubilc interface)
当我们导入模块时,程序会查看这个变量,只将变量列出的内容导入
如果不设置这个变量,那么程序会导入所有不以下划线开头的全局名称

In [30]:
copy.__all__
Out[30]:
['Error', 'copy', 'deepcopy']

help函数获取帮助

In [31]:
help(copy.copy)
Help on function copy in module copy:

copy(x)
    Shallow copy operation on arbitrary Python objects.
    
    See the module's __doc__ string for more info.


In [32]:
#通过函数的__doc__特性获取文档信息
print copy.copy.__doc__
Shallow copy operation on arbitrary Python objects.

    See the module's __doc__ string for more info.
    

更多参考信息,可以从http://python.org/doc/lib 获取

In [33]:
#查看源代码,通过检查模块的__file__属性获取模块的路径,然后用文本编辑器打开
print copy.__file__
/usr/lib/python2.7/copy.pyc

In [34]:
#但是有部分模块是融入解释器的,不可阅读
#也有的模块是用C语言写成的
In []: