2015/9/15 Python基础(12):模块和包

模块是用来组织 Python 代码的方法,而包则是用来组织模块的。

当代码量很大时,我们一般会把代码分成几个有组织的代码段,然后每个代码段之间有一定的联系。代码单之间是共享的,所以Python允许调入一个模块,允许使用其他模块的属性利用之前的工作成果,实现代码重用。那些自我包含并且有组织的代码片段就是模块(module),将其他模块中属性附加到你的模块中的操作较导入(import)

模块是逻辑上的说法,而它们在物理层是一个个独立的文件,模块的文件名就是模块的名字加拓展名.py。与其他可以导入类的语言不同,Python中你导入的是模块或模块属性。

模块的名称空间
模块名称是他们属性名称中的一个重要部分,给定一个模块名后,只可能有一个模块被导入到Python解释器中,所以不同模块间不能出现名称交叉现象。如果在模块mymodule里创建了一个atoi()函数,那么它的名字应该是 mymodule.atoi()。所以即使属性之间有名称冲突,但他们的完整授权名称通过句点属性标识指定了各自的名称空间,防止名称冲突产生。

模块的导入需要一个路径搜索的过程。即在文件的“预定义区域”中查找 mymodule.py 文件(如果导入的是mymodule的话)。这些预定义区域不过是你的 Python 搜索路径的集合。路径搜索和搜索路径概念不同,前者指查找某个文件,后者是去查找一组目录。
默认的搜索路径是在编译或是安装时指定的,它可以在一个或两个地方修改。
一个是启动Python的shell命令行的PYTHONPATH环境变量。该变量的内容是一组用冒号分隔的目录路径。如果你想让解释器使用这个变量,请确保在启动解释器或执行Python脚本前设置或修改了该变量。
解释器启动之后,也可以访问这个搜索路径,它会被保存在 sys 模块的 sys.path 变量里。
不过它已经不是冒号分隔的字符串,而是包含每个独立路径的列表。
这只是个列表,所以可以随时随地对它修改,如果需要知道你要导入的模块是什么,而它的路径不再搜索路径里,那么只需调用append()方法即可。
修改完成后,你就可以加载自己的模块了。只要列表中的某个目录包含这个而文件,它就会被正确导入。
在同一个模块的多个拷贝都出现在路径中时,会使用沿用搜索路径找到的第一个模块。

名称空间
名称空间是名称(标识符)到对象的映射。向名称空间添加名称的操作过程涉及到绑定标识符到指定对象的操作(以及给该对象的引用计数加1)。
Python在执行期间由两个或三个活动的名称空间,分别是局部名称空间,全局名称空间和内建名称空间。
Python解释器会首先加载内建名称空间,它由 __builtins__ 模块的名字构成。随后加载执行模块的全局名称空间,他会在模块开始执行后变为活动名称空间。如果在执行期间调用了一个函数,那么将创建出第三个名称空间,局部名称空间。

关于__builtins__ 和 __builtin__
现在尽可能只使用 __builtins__ ,不使用__builtin__ ,现在所有__builtin__的内容都在__builtins__里有,而__builtin__已经不太支持。

名称空间与变量作用域的关系
名称空间是纯粹意义上的名字和对象间的映射关系,而作用域还指出了从用户代码的那些物理位置可以访问到这些名字。
名称查找、确定作用域和覆盖
名称查询将确定作用域的规则覆盖到名称空间。访问一个属性时,解释器必须在三个名称空间中的一个里找到它,先从局部名称空间开始,如果没有找到,解释器会继续查找全局名称空间,如果失败了,将在内建名称空间里查找。如果都没找到,返回一个NameError。
这种先后查找的方式是遮蔽了之后的名称空间。也就是局部变量覆盖了全局变量:

def foo():
  print "calling foo()..."
  bar = 200
  print "in foo(), bar is",bar
bar = 100
print "in __main__, bar is", bar
foo()
print "in __main__, bar is", bar

结果是:

>>>
in __main__, bar is 100
calling foo()...
in foo(), bar is 200
in __main__, bar is 100

如果如下代码:

def foo():
  print "calling foo()..."
  print "before we assign bar,bar is",bar
  bar = 200
  print "in foo(), bar is",bar
bar = 100
print "in __main__, bar is", bar
foo()
print "in __main__, bar is", bar

则返回:

>>>
in __main__, bar is 100
calling foo()...
before we assign bar,bar is

Traceback (most recent call last):
File "F:/桌面/PythonProgram/namespace.py", line 8, in <module>
foo()
File "F:/桌面/PythonProgram/namespace.py", line 3, in foo
print "before we assign bar,bar is",bar
UnboundLocalError: local variable ‘bar‘ referenced before assignment

如果删除其中一行:

def foo():
  print "calling foo()..."
  print "before we assign bar,bar is",bar
  print "in foo(), bar is",bar
bar = 100
print "in __main__, bar is", bar
foo()
print "in __main__, bar is", bar

则结果为:

>>>
in __main__, bar is 100
calling foo()...
before we assign bar,bar is 100
in foo(), bar is 100
in __main__, bar is 100

上面的尝试里,反映出了局部名称空间覆盖了全局名称空间的过程。当我在函数中给bar赋值后,bar变成局部变量,也就是出现在局部名称空间里,此时在给bar赋值前调用它就会报错。

导入模块
导入语句有两种:

import module1
import module2
...或

import module1,module2,...

这两种没有太大的不同,只有可读性的差别。

核心风格:一般我们推荐所有的模块在开头导入,最好按这样的顺序
Python标准库模块
Python第三方模块
应用程序自定义模块
然后用一个空行分割这三个模块的导入语句

from-import语句
这是导入模块的指定属性。也就是把指定名称导入到当前作用域,语法如下:

from module import name1[,name2,...]

导入内容过长变成多行导入时,用一个\可以换行。

拓展import语句(as)
当你想使用一个模块或者模块属性,但想改一个名字时,可以使用自己要的名字替换模块的原始名字,语法如下:

import longmodulename as yourname

from-import语句可以把名字导入到当前空间去,不需要在使用时加句点属性标识符,如果要把所有的名称都导入到当前名称空间可以用:

from module import *

当然,从实践中来看,这不是很好的编程风格,它污染了当前名称空间,很可能覆盖当前名称空间现有的名字。

模块内建函数
__import__()
这是import的实际函数,我们使用它来完成导入工作,而提供这个函数是为了让有特殊需求的用户来覆盖它,实现自定义导入。
__import__()语法是:

__import__(module_name[,globals[, locals[, fromlist[]]]])

module_name 是导入模块的名字,globals 是包含当前全局符号表的名字的字典, locals 是包含局部符号表的名字的字典, fromlist是一个使用from-import 语句所导入符号的列表。

globals() 和 locals()
这两个内建函数分别返回调用者全局和局部名称空间的字典。
在全局名称空间下,globals() 和 locals() 返回相同的字典,因为局部名称空间就是全局空间。

reload()
这个内建函数可以重新导入一个已经导入的模块。语法是:

reload(module)

模块中的代码在导入时被执行,但只执行一次。以后执行 import 语句不会再次执行这些代码,只是绑定模块名称。而 reload()可以多次执行。


包是一个有层次的文件目录结构,它定义了一个由模块和子包组成的 Python 应用程序执行环境。
可以解决如下问题:
为平坦的名称空间加入有层次的组织结构
允许程序员把有联系的模块组合到一起
允许分发者使用目录结构而不是一大堆混乱的文件
帮助解决有冲突的模块名称
包也使用句点属性标识来访问他们的元素。

假设有这样的包
Phone/
  __init__.py
  common_util.py
  Voicedta/
    __init__.py
    Pots.py
    Isdn.py
  Fax/
    __init__.py
    G3.py
  Mobile/
    __init__.py
    Analog.py
    digital.py
  Pager/
    __init__.py
    Numeric.py
可以这样导入包:

import Phone.Mobile.Analog
Phone.Mobile.Analog.dial()
或
from Phone import Mobile
Mobile.Analog.dial()
或
from Phone.Mobile import Analog
Analog.dial()
或
from Phone.Mobile.Analog import dial
dial()

上面的目录结构中有很多__init__.py文件。这是初始化模块,导入子包时from-import语句要用到它。如果没有用到,他们可以是空文件。

绝对导入
因为包的使用越来越广发,很多情况下导入子包会和标准库模块发生冲突,包模块会把名字相同的标准库模块隐藏掉。为此,所有的导入现在都被认为是绝对的,也就是说这些名字必须通过Python路径来访问。
当然,也留下了一定的相对导入操作,第一部分是句点,表示相对导入,然后用附加句点表示在哪个位置级别。
如上的目录结构,如果我们在Digital.py中,有以下的导入方法:

from Phone.Mobile.Analog import dial #绝对导入
from .Analog import dial
from ..common_util import setup
form ..Fax import G3.dial
时间: 2024-10-19 23:37:05

2015/9/15 Python基础(12):模块和包的相关文章

带你学python基础:模块和包

一.什么是模块 在我们平时的开发过程中,或多或少会用到 Python 的一些内置的功能,或者说,还会用到一些第三方的库,我们用到的这些 Python 的内置的功能,和一些第三方的库,就可以说是一些模块了. 例如,我们在读写文件的时候,我们就会用到文件操作的模块os. 是不是经常遇到呢?模块,来了! 其实,每一个 Python 脚本文件都可以被当成是一个模块. 模块以磁盘文件的形式存在.当一个模块变得过大,并且驱动了太多功能的话,就应该考虑拆一些代码出来另外建一个模块. 模块里的代码可以是一段直接

Python基础day-16[模块与包]

模块: 模块的好处:首先模块可以大大提高代码的可维护性,其次可以减少大量的重复代码,可以通过模块调用来重复使用某些代码.另外,模块还可以避免函数名和变量名冲突. 在Python中一个.py文件就称之为一个模块(module). 模块分类: Python标准库(内置库) 第三方模块 应用程序自定义模块 导入模块 注:模块的在import的时候,会执行模块内的所有代码,并新建一个名称空间保存这些.类似变量,重复导入同一模块,不会重复执行模块内代码. 所以导入时进行了两步操作: 1.创建新的名称空间

python基础之模块与包

一.模块 1.什么是模块?一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 2 为何要使用模块? 如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script. 随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理.这时我们不仅仅可以把这些文件当

python 基础之 模块

Python 基础之模块 一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 就是一个python文件中定义好了类和方法,实现了一些功能,可以被别的python文件所调用 那么如何使用一个模块呢? 当然是使用import 模块名 这个方式加载一个模块了 ,比如:import time 如果要使用模块中的类,就是: 模块名 点儿 类 比如: import modle.Teacher 那么如果模块中的方法不知道是做什么用的怎么办呢?     两种方法:    

python之路--模块和包--景丽洋

python之路--模块和包 阅读目录 一 模块 3.1 import 3.2 from ... import... 3.3 把模块当做脚本执行 3.4 模块搜索路径 3.5 编译python文件 二 包 2.2 import 2.3 from ... import ... 2.4 __init__.py文件 2.5  from glance.api import * 2.6 绝对导入和相对导入 2.7 单独导入包 回到顶部 一 模块 1 什么是模块? 常见的场景:一个模块就是一个包含了pyth

what&#39;s the python之自定义模块和包

模块自定义 上节说了有关模块的知识,当时所说的模块都是内置模块,现在来看自己定制的模块,即模块也可以自定义. 模块的自定义就是指写一段python文件,一般情况下里面包含了可执行的语句和函数的定义,其实自定义的模块和内置模块的效果一样,都是使以后程序的操作更加方便,不用重复敲一样的代码,直接导入模块就可以使用.导入方式与内置模块相同,import+文件名,当然,自定义的模块增加了许多其他的导入方式,下文我们会详细介绍. 需要特别注意的是:我们自定义的模块名不应该与系统内置模块重名. 现在我们来自

2015/8/31 Python基础(5):字符串

字符串是Python最常见的一种类型.通过在引号间包含字符的方式创建它.Python里单双引号的作用是一致的.Python的对象类型里不存在字符型,一般用单个字符的字符串来使用.Python的字符串是一种直接量或者说标量,Python解释器在处理字符串时把它作为单一值并且不会包含其他Python类型的.Python的字符串也是不可改变类型.字符串里的字符可以通过切片操作访问.Python有3类字符串,通常意义字符串(str),Unicode字符串(unicode)和抽象类字符串(basestri

2015/9/9 Python基础(10):文件和输入输出

文件对象文件对象不仅可以用来访问普通的磁盘文件,而且也可以访问其它任何类型抽象层面上的“文件”.一旦设置了合适的“钩子”,你就可以访问文件类型接口的其它对象,就好像访问的是普通文件一样.文件对象的处理要以来很多内建函数,还有很多函数会返回文件对象或者是类文件对象.进行这种轴向处理的主要原因是许多输入/输出数据结构更趋向于使用通用的接口.这样就可以在程序行为和实现上保持一致性.文件只是连续的字节序列,数据传输经常会用到字节流,无论字节流是由单个字节还是大块数据组成. 文件内建函数[open()和f

python基础之模块二

六 logging模块 6.1 函数式简单配置 import logging #导入模块 logging.debug('debug message') #调试消息 logging.debug('info message') #导入消息 logging.debug('warning message') #警告消息 logging.error('error message') #错误消息 logging.critical('critical message') #严重信息 默认情况下python的l