21 November 2013

模块基础

模块通过使用自包含的变量包,即命名空间提供了将部件组织为系统的简单方法。

一个模块文件的顶层定义的所有变量名都成了被导入的模块对象的属性。

关键字

  1. import:以整体导入一个模块
  2. from:从模块文件中导入特定的变量名
  3. imp.reload:在不中止Python程序的前提下,重新导入模块文件代码。

程序第一次导入指定文件时,会执行的三个步骤

  1. 搜索模块文件
  2. 编译成字节码(可选):首先检查文件时间戳,如果字节码文件比源文件旧,则将源文件编译才.pyc的字节码。只有被导入的源文件才需要编译,顶层执行的文件的字节码在内部使用后丢弃。
  3. 执行模块的代码:所有语句依次执行。包括函数、类的定义,以及所有普通程序代码,如print等。

默认情况下,任何模块每个进程只会导入一次,之后的导入都会跳过上面的三个步骤,重用已加载到内存中的模块。

路径搜索

  1. 程序的主目录
  2. PYTHONPATH 环境变量(如果设置)
  3. 标准链接库目录
  4. 任何.pth文件的内容(如果存在)

可以通过sys.path查看当前程序的实际搜索路径配置。

模块文件选择

  1. 源文件.py
  2. 字节码文件
  3. 目录,包导入
  4. 编译扩展
  5. 用C编写的内置模块,并通过静态链接至Python
  6. ZIP文件组,导入时自动解压
  7. 内存内映像,
  8. Java类,Jython版本的Python;.NET 组件,IronPython版本的Python中。

模块导入

from实际只是扩展了import语句而已。多了一个步骤:将文件中一个或多个变量名从文件中复制出来。

from module import name1, name2

# 上面语句与下面的是等效的

import module
name1 = module.name1
name2 = module.name2
del module

import和from都是赋值语句 - import将整个模块对象赋值给一个变量名 - from将一个或多个变量名赋值给另一个模块中同名的对象

  • 为了实际修改另一个文件中的全局变量名,必须使用import。
  • 引用不同模块内定义的相同变量名时,必须使用import。

from语句的缺点:

  • 可能会破坏命名空间。如果使用from导入的变量名与当前作用域中现有变量同名,则会被覆盖。尤其时from module import *,可能会存在此问题。
  • 和reload同时使用会出现严重问题。from导入的变量名引用仍然是reload之前的对象。from module import *会把一个命名空间融入到另一个,所以会使得模块命名空间的分割特性失效。

建议:简单模块一般用import,严格限制每个文件至多只能用一次from *

导入与作用域

  • 不直接导入一个文件,就无法直接存取该文件捏所定义的变量名。
  • 一段程序的作用域完全有程序所在文件内实际位置决定。作用域绝不会被函数调用或模块导入影响。

重载模块 reload()

Python2.x与3.x区别:2.x中reload是一个内置函数,3.x中reload则要从模块imp中导入。

reload目前只能用在Python编写的模块;用其他语言编写的扩展模块可以动态加载,但是不能重载。

reload()一些细节:

  • reload()会在模块当前命名空间内执行模块文件的新代码
  • 文件中顶层赋值语句会使得变量名换成新值。
  • 重载会影响所有使用import导入模块的客户端。
  • 重载只对以后使用from的客户端造成影响,之前使用from的客户端不受影响依然引用重载前的就对象。

模块包

__name__变量可以检查出模块本身时作为程序运行还是导入到其他程序中。如果__name__==__main__,模块作为程序运行的。

包:另一类模块,可以简单的看成是一个包含了__init__.py文件的目录。一个包可以包含多个模块。

dir函数,将对象(以及模块的所有函数、类、变量等)所有特性全部列出来。

__all__变量定义了模块的公有接口,即:from xxx import *可以导入的所有函数或变量名。如果没有定义__all__则用import *默认将所有不以下滑线开头的全局名称。

包相对导入




blog comments powered by Disqus