Python基础:26模块
一:模块和文件
1:模块是逻辑上组织 Python 代码的方法,文件是物理层上组织模块的方法。因此,一个文件被看作是一个独立模块,一个模块也可以被看作是一个文件。 模块的文件名就是模块的名字加上扩展名 .py。
2:从基本概念来说,一个名称空间就是一个从名称到对象的关系映射集合。每个模块都定义了它自己的唯一的名称空间。所以,即使有两个模块中,有相同名称的函数atoi,但它们的完整授权名称(fully qualified name)——通过句点属性标识指定了各自的名称空间——防止了名称冲突的发生。
3:模块的导入需要一个"路径搜索"的过程。即在文件系统"预定义区域"中查找mymodule.py文件的过程。这些预定义区域是 Python 搜索路径的集合。
有时候导入模块操作会失败:
>>> import xxx
Traceback (innermost last):
File "<interactive input>",line 1,in ?
ImportError: No module named xxx
发生这样的错误时,意味着解释器无法访问请求的模块,可能的原因是模块不在搜索路径里,从而导致了路径搜索的失败。
默认搜索路径是在编译或是安装时指定的。可以在一个或两个地方修改。
一个是启动Python 的 shell 或命令行的 PYTHONPATH环境变量。该变量的内容是一组用冒号分割的目录路径。如果想让解释器使用这个变量,那么必须在启动解释器或执行 Python 脚本前手动设置或修改该变量。否则该变量为空。
解释器启动之后,也可以访问这个搜索路径,它会被保存在 sys 模块的sys.path 变量里。比如下面是一个 Unix 搜索路径的样例:
>>> sys.path
['','/usr/local/lib/python2.x/','/usr/local/lib/ python2.x/plat-sunos5','/usr/local/lib/python2.x/lib-tk','/usr/local/lib/python2.x/lib-dynload','/usr/local/lib/Python2.x/site-packages',]
注意该列表的第一个元素为空字符串,它对应着当前目录。
这只是个列表,所以可以随时随地对它进行修改。如果知道需要导入的模块是什么,而它的路径不在搜索路径里,那么只需要调用列表的 append() 方法即可,就像这样:sys.path.append('/home/wesc/py/lib')。修改完成后,就可以加载自己的模块了。
如果有一个模块的很多拷贝。解释器会使用沿搜索路径顺序找到的第一个模块。
使用sys.modules 可以找到当前导入了哪些模块和它们来自什么地方。sys.modules 是一个字典,使用模块名作为键(key) ,对应物理地址作为值( value )。
二:名称空间
1:名称空间是名称(标识符)到对象的映射。向名称空间添加名称的操作过程涉及到绑定标识符到指定对象的操作,以及给该对象的引用计数加 1 。
程序执行期间有两个或三个活动的名称空间。这三个名称空间分别是局部名称空间,全局名称空间和内建名称空间,但局部名称空间在执行期间是不断变化的,所以说是"两个或三个"。
Python 解释器首先加载内建名称空间。 它由 __builtins__ 模块中的名字构成。随后加载执行模块的全局名称空间,它会在模块开始执行后变为活动名称空间。如果在执行期间调用了一个函数,那么将创建出第三个名称空间,即局部名称空间。
可以通过 globals() 和 locals() 内建函数判断出某一名字属于哪个名称空间。
2:访问一个属性时,解释器必须在三个名称空间中的一个能找到它。首先从局部名称空间开始,如果没有找到,将继续查找全局名称空间。如果这也失败了,它将在内建名称空间里查找。如果最后的尝试也失败了,会得到这样的错误:
>>> foo
Traceback (innermost last): File "<stdin>",line 1,in ?
NameError: foo
因此,局部名称空间中找到的名字会隐藏全局或内建名称空间的对应对象。这就相当于"覆盖"了那个全局变量。
3:无限制的名称空间
Python的一个有用的特性在于,可以在任何需要放置数据的地方获得一个名称空间。可以在任何时候给函数添加属性(使用熟悉的句点属性标识)。比如:
def foo():
pass foo.__doc__ = 'Oops,forgot to add doc str above!'
foo.version = 0.2
这对于类和模块也是一样的。可以把任何想要的东西放入一个名称空间里。
三:导入模块
1:import语句
使用 import 语句导入模块,语法如下所示:
import module1
import module2
......
import moduleN
也可以在一行内导入多个模块:
import module1[, module2[,... moduleN]]
但是这样的代码可读性不如多行的导入语句。而且在性能上和生成 Python 字节代码时没什么优势。所以推荐使用第一种格式。
推荐所有的模块在 Python 模块的开头部分导入。而且最好按照这样的顺序:
Python 标准库模块;Python 第三方模块;应用程序自定义模块;然后使用一个空行分割这三类模块的导入语句。
解释器执行到import语句, 如果在搜索路径中找到了指定的模块, 就会加载它。该过程遵循作用域原则, 如果在一个模块的顶层导入, 那么它的作用域就是全局的;如果在函数中导入, 那么它的作用域是局部的。
如果模块是被第一次导入, 它将被加载并执行。在这样的语句中,调用方法必须是:module.name
2:from-import语句
可以在模块中导入指定的模块属性。也就是把指定名称导入到当前作用域。语法是:
from module import name1[,name2[,... nameN]]
这样的导入方法,访问属性时,直接使用name即可,不能使用module.name的方式。因为解释器不能识别module。
这样的导入方式,也会执行顶层代码。而且,除了导入的name之外,其他的属性也是不可访问的。当然,name也可以引用本模块的其他符号,不会出错。比如下面的例子:
#test.py
print 'this is test1' def foo():
print 'this is foo, call bar now'
bar() def bar():
print 'this is bar' print 'this is test2' >>> from test import foo
this is test1
this is test2 >>> foo()
this is foo, call bar now
this is bar >>> bar()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'bar' is not defined
从一个模块导入许多属性时,import 行会很长,需要一个’/’。比如:
from Tkinter import Tk, Frame, Button, Entry, Canvas, \
Text, LEFT, DISABLED, NORMAL,RIDGE, END
也使用多行的 from-import 语句:
from Tkinter import Tk, Frame, Button, Entry, Canvas, Text
from Tkinter import LEFT, DISABLED, NORMAL, RIDGE, END
3:别名
如果不想使用导入的名字,可以使用自己想要的名字替换模块的原始名称。使用扩展的 import , 就可以在导入的同时指定局部绑定名称。类似这样:
import Tkinter
from cgi import FieldStorage
. . . 可以替换为 . . .
import Tkinter as tk
from cgi importFieldStorage as form
四:模块导入的特性
1:加载模块会导致这个模块被"执行"。也就是被导入模块的顶层代码将直接被执行。这通常包括设定全局变量以及类和函数的定义。如果有检查__name__的操作, 那么它也会被执行。
当然,这样的执行可能不是我们想要的结果。应该把尽可能多的代码封装到函数。明确地说,良好的模块编程习惯是只把函数和模块定义放入模块的顶层。
2:一个模块可以导入多次,但是它只被加载一次,这可以阻止多重导入时,代码被多次执行。例如你的模块导入了 sys 模块, 而你要导入的其他模块也导入了它, 那么,加载只在第一次导入时发生。
3:调用 from-import 可以把名字导入当前的名称空间里去,可以把指定模块的所有名称导入到当前名称空间里:from module import *
但是, "from module import *" 不是良好的编程风格, 因为它"污染"当前名称空间, 而且很可能覆盖当前名称空间中现有的名字。
只从模块导入名字的另一个副作用是,那些名字会成为局部名称空间的一部分。 这可能导致覆盖一个已经存在的具有相同名字的对象。对这些变量的改变只影响它的局部拷贝而不是所导入模块的原始名称空间。比如下面的例子
#############
# imptee.py #
#############
foo = 'abc' def show():
print 'foo from imptee:', foo #############
# impter.py #
#############
from imptee import foo,show
show()
foo = 123
print 'foo from impter:', foo
show()
运行impter.py,发现从被导入者的观点看, 它的 foo 变量没有改变:
foo from imptee: abc
foo from impter: 123
foo from imptee: abc
唯一的解决办法是使用 import 和完整的标识符名称(句点属性标识)。
4:由于改进,新特性,以及当前特性增强, 某些变化会影响到当前功能。所以为了让 Python 程序员为新事物做好准备, Python 实现了 __future__ 指令。
使用 from-import 语句"导入"新特性, 用户可以尝试一下新特性或特性变化, 以便在特性固定下来的时候修改程序。 它的语法是:
from __future__ import new_feature
注意,只 import __future__ 不会有任何变化,必须显示地导入指定特性。
5:在 2.3 版中, Python 加入了从 ZIP 归档文件导入模块的功能。如果搜索路径中存在一个包含 Python 模块(.py, .pyc, or .pyo 文件)的 .zip 文件, 导入时会把 ZIP 文件当作目录处理, 在文件中搜索模块。
五:模块内建函数
1:__import__()
import 语句会调用__import__() 函数完成它的工作。提供这个函数是为了让有特殊需要的用户覆盖它, 实现自定义的导入算法。它的语法是:
__import__(module_name[, globals[, locals[, fromlist]]])
module_name 变量是要导入模块的名称, globals 是包含当前全局符号表的名字的字典, locals 是包含局部符号表的名字的字典, fromlist 是一个使用 from-import 语句所导入符号的列表。globals , locals , 以及 fromlist 参数都是可选的, 默认分别为 globals() , locals() 和 [] 。
比如,调用 import sys 语句可以使用下边的语句完成:
sys = __import__('sys')
2:globals() 和locals()
globals() 和locals() 内建函数分别返回调用者全局和局部名称空间的字典。 在一个函数内部, 局部名称空间代表在函数执行时候定义的所有名字,locals() 函数返回的就是包含这些名字的字典。 globals() 会返回函数可访问的全局名字。
在全局名称空间下, globals() 和 locals() 返回相同的字典, 因为这时的局部名称空间就是全局空间。 例子如下:
def foo():
print '\ncalling foo()...'
aString = 'bar'
anInt = 42
print "foo()'s globals:", globals().keys()
print "foo()'s locals:", locals().keys() print "__main__'sglobals:", globals().keys()
print "__main__'slocals:", locals().keys()
foo()
执行这个脚本, 得到如下的输出:
__main__'s globals: ['__doc__','foo', '__name__', '__builtins__']
__main__'s locals: ['__doc__', 'foo','__name__', '__builtins__']
calling foo()...
foo()'s globals: ['__doc__', 'foo', '__name__', '__builtins__']
foo()'s locals: ['anInt', 'aString']
3:reload()
reload() 内建函数可以重新导入一个已经导入的模块。 语法如下:
reload(module)
module 是想要重新导入的module对象,它之前必须已经被成功的全部导入(不是使用 from-import)。否则解释器会无法识别module。 module必须是模块自身而不是包含模块名的字符串。 也就是说必须类似 reload(sys) 而不是 reload('sys')。
该函数返回module对象。该函数的作用如下:修改了模块的源代码,在不离开当前python解释器的情况下,使用修改后的新版本。
注意,reload() 函数在每次调用时,都会执行模块的顶层代码。这不同于import语句。
六:包
包是一个有层次的文件目录结构, 它用来帮助解决如下问题:
为平坦的名称空间加入有层次的组织结构
允许程序员把有联系的模块组合到一起
允许分发者使用目录结构而不是一大堆混乱的文件
帮助解决有冲突的模块名称
与类和模块相同, 包也使用句点属性标识来访问他们的元素。使用标准的import 和 from-import 语句导入包中的模块。
1:目录结构
假定包的例子有如下的目录结构:
Phone/
__init__.py
common_util.py
Voicedta/
__init__.py
Pots.py
Isdn.py
Fax/
__init__.py
G3.py
Mobile/
__init__.py
Analog.py
igital.py
Pager/
__init__.py
Numeric.py
Phone 是最顶层的包, Voicedta等是它的子包。可以只导入顶层的子包, 然后使用属性/点操作符向下引用子包树:
from Phone import Mobile
Mobile.Analog.dial('555-1212')
可以一直沿子包的树状结构导入:
from Phone.Mobile.Analog import dial
dial('555-1212')
为了让Python 将目录当做包,目录下必须包含 __init__.py 文件;最简单的情况下,__init__.py 可以只是一个空的文件,但它也可以为包执行初始化代码或设置__all__变量, from-import 语句导入子包时需要用到它。
程序员经常忘记为它们的包目录加入 __init__.py 文件, 所以从Python 2.5 开始, 这将会导致一个ImportWarning信息。不过, 除非给解释器传递了 -Wd 选项, 否则它会被简单地忽略。
2:包同样支持 from-import all 语句:from package.module import *
然而, 这样的语句会导入哪些文件取决于操作系统的文件系统。所以可以在__init__.py 中加入 __all__ 变量。该变量包含执行这样的语句时应该导入的模块的名字。它由一个模块名字符串列表组成。
3:绝对导入和相对导入
绝对导入是指,为了避免导入子包覆盖掉标准库模块(由于名字相同,发生冲突),所以规定import语句只能导入绝对路径的模块(从sys.path或PYTHONPATH导入),无法通过直接import包名字来导入隔壁包的模块。
也就是说你在项目的某层里想导入隔壁包的某模块,需要从项目的根那一层一直点到当前的层级,然后再导入隔壁的包。比如在/Alpha/Beta/Gamma中导入/Alpha/Beta/Delta 包,就要import Alpha.Beta.Delta
绝对导入特性从2.7版本开始成为默认功能,import语句总是绝对导入的。
相对导入只应用于 from-import 语句,在包名字的前面加一个点,表示从当前层级下的某包导入。
比如在/Alpha/Beta/Gamma 中导入/Alpha/Beta/Delta包中的模块,可以写成:from .Delta import xxx
在包的名字前加两个点,表示从上一层级里的某包导入。比如在/Alpha/Beta/Gamma 中导入/Alpha/Sigma 包中的模块,可以写成
from ..Sigma import xxx
在开启了absolute_import特性之后,存在相对导入语句的模块,不能直接运行,会报错。
七:其他特性
1:自动载入的模块
当 Python 解释器在标准模式下启动时, 一些模块会被解释器自动导入,用于系统相关操作。
sys.modules 变量包含一个由当前载入(完整且成功导入)到解释器的模块组成的字典, 模块名作为键, 它们的位置作为值。
例如在 Windows 下:
>>> import sys
>>> sys.modules.keys()
['os.path', 'os', 'exceptions', '__main__', 'ntpath', 'strop', 'nt','sys', '__builtin__', 'site', 'signal', 'UserDict', 'string', 'stat']
Unix 下载入的模块很类似:
>>> import sys
>>> sys.modules.keys()
['os.path', 'os', 'readline', 'exceptions', '__main__', 'posix', 'sys','__builtin__', 'site', 'signal', 'UserDict', 'posixpath', 'stat']
2:如果不想让某个模块属性被 "from module import *" 导入 , 那么你可以给你不想导入的属性名称加上一个下划线( _ )。
不过如果导入了整个模块或是你显式地导入某个属性(如importfoo._bar ), 这个隐藏数据的方法就不起作用了。
3:从 Python 2.3 开始,Python 的模块文件开始支持除 7 位 ASCII 之外的其他编码。 当然ASCII 是默认的。
只要在 Python 模块头部加入一个额外的编码指示说明,就可以让导入者使用指定的编码解析你的模块, 编码对应的 Unicode 字符串。 所以使用纯 ASCII 文本编辑器的时候不需要担心了。一个 UTF-8 编码的文件可以这样指示:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
如果你执行或导入了包含非 ASCII 的 Unicode 字符串而没有在文件头部说明, 那么会在Python 2.3 得到一个 DeprecationWarning , 而在 2.5 中这样做会导致语法错误。
4:如果模块 omh4cli 尝试导入 cli4vof , 而模块 cli4vof 也试着导入 omh4cli 。则最后谁也不会完成导入工作, 引发错误。
这是一个导入循环的例子,解决这个问题,需要移除其中一个导入语句。
Python基础:26模块的更多相关文章
- python基础——第三方模块
python基础——第三方模块 在Python中,安装第三方模块,是通过包管理工具pip完成的. 如果你正在使用Mac或Linux,安装pip本身这个步骤就可以跳过了. 如果你正在使用Window ...
- python基础——使用模块
python基础——使用模块 Python本身就内置了很多非常有用的模块,只要安装完毕,这些模块就可以立刻使用. 我们以内建的sys模块为例,编写一个hello的模块: #!/usr/bin/env ...
- 二十六. Python基础(26)--类的内置特殊属性和方法
二十六. Python基础(26)--类的内置特殊属性和方法 ● 知识框架 ● 类的内置方法/魔法方法案例1: 单例设计模式 # 类的魔法方法 # 案例1: 单例设计模式 class Teacher: ...
- 二十五. Python基础(25)--模块和包
二十五. Python基础(25)--模块和包 ● 知识框架 ● 模块的属性__name__ # my_module.py def fun1(): print("Hello& ...
- python 基础之 模块
Python 基础之模块 一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 就是一个python文件中定义好了类和方法,实现了一些功能,可以被别的python文 ...
- 【Python之路】第六篇--Python基础之模块
模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个函数才 ...
- python基础-7模块,第三方模块安装方法,使用方法。sys.path os sys time datetime hashlib pickle json requests xml
模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个函数才 ...
- 周末班:Python基础之模块
什么是模块 什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用python编写 ...
- python基础-各模块文章导航
python基础学习日志day5-各模块文章导航 python基础学习日志day5---模块使用 http://www.cnblogs.com/lixiang1013/p/6832475.html p ...
- python基础----常用模块
一 time模块(时间模块)★★★★ 时间表现形式 在Python中,通常有这三种方式来表示时 ...
随机推荐
- C++/CLI 创建WPF程序
本文简单演示下用C++/CLI创建WPF程序,IDE为VS2015 首先创建CLR项目,选择CLR空项目: 然后,右键源文件,选择新建class,选择CLR->Component Class 接 ...
- Constructing Roads POJ - 2421 (最小生成树)
思路:首先使用二维数组dis[][]处理输入, 对于已经修好的路,将其对应的dis[i][j]置为零即可.最后再将 所有的dis[][]保存到边结构体中,使用Kruskal算法求得最小生成树. ...
- NACOS集群搭建遇到的问题
搭建NACOS官网教程: https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html 这里说的很详细了.也有中文的.我就记录一下在搭建集群的时候 ...
- 木卯先生的笔记---Date类、DateFormat类和Calendar类
1.Date类 1.1 简介 Date类是 java.util 包下面的类,表示特定的瞬间,精确到毫秒. 1.2 方法 1.2.1 Date() 构造方法 public Date() :分配 Date ...
- Ubuntu18.04 修改IP地址、查看网关、防火墙
1. Ubuntu18.04 修改IP地址 修改 sudo vim /etc/netplan/50-cloud-init.yaml文件 # This file is generated from in ...
- CLTPHP5.0发布
CLTPHP内容管理系统,包含系统设置,权限管理,模型管理,数据库管理,栏目管理,会员管理,网站功能,模版管理,微信管理等相关模块. CLTPHP内容管理系统=ThinkPHP5+layuiAdm ...
- OpenLayers使用点要素作为标记
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...
- jQuery Scroll Path 滚插视图酷炫
jQuery Scroll Path是一个jQuery的滚动路径插件,可以让你自定义滚动路径.该插件是使用canvas flavored的语法来绘制路径.可以通过鼠标滚轮上/下箭头键和空格键来查看路径 ...
- 【水滴石穿】ReactNative-Redux-Thunk
老实说,运行出来的项目让人失望,毕竟我想看各种有趣的demo啊- 先放上源码地址:https://github.com/ludejun/ReactNative-Redux-Thunk 我们来一起看看代 ...
- JS运算的优先级
汇总表 下面的表将所有运算符按照优先级的不同从高到低排列. 优先级 运算类型 关联性 运算符 20 圆括号 n/a ( … ) 19 成员访问 从左到右 … . … 需计算的成员访问 从左到右 … [ ...