标签:python 模块
参考:https://www.cnblogs.com/bobo0609/p/6938012.html
https://docs.python.org/2/tutorial/modules.html
1.简介:
在Python中,一个.py或者.pyc文件就称之为一个模块(Module)。即一个文件被看作一个独立的模块,一个模块也可以被看做是一个文件
.py:存放的是python源码
.pyc:存放的是python解释器对源码编译后的字节码
python把文件名去掉.py/.pyc后缀作为模块名,比如 os.py ,那么它的模块名就是 os
那么假设我们当前路径有个os.py,python怎么知道它的位置,并导入使用呢?
这里就涉及到python的模块搜索路径,它的搜索次序如下:
<1>当前路径
<2>PYTHONPATH变量自定义的路径(PYTHONPATH是系统自定义的环境变量,类似centos中的PATH)
<3>安装python时所定义的路径
有人会疑惑,python怎么知道我当前的路径在哪?
这是因为,python的程序包括一个顶层程序文件和其它的模块文件,这个顶层文件相当于程序执行的入口,类似shell脚本,我们执行脚本时必须写明绝对路劲或者切到对应路径去执行(这个时候路径就传递了),python也是同理
例子:
[root@cqhdtest python_learn]# pwd /root/python_learn [root@cqhdtest python_learn]# cat getvalue.py #!/usr/local/anaconda2/bin/python x='Gx' y='Gy' z='Gz' def f1(x,y,z): x='Ex' z='Ez' print x,y,z def f2(x,y,z): x='Lx' print x,y,z f2(x,y,z) f1(x,y,z) [root@cqhdtest python_learn]# cat index.py import getvalue print x [root@cqhdtest python_learn]# python index.py Ex Gy Ez Lx Gy Ez Traceback (most recent call last): File "index.py", line 2, in <module> print x NameError: name 'x' is not defined
这里index.py作为程序入口导入了getvalue这个模块,显然,这里python找到了getvalue模块,因为程序执行到了print x,但是为什么会有"Ex Gy Ez"这些输出呢?
这是因为:python在首次导入模块(import 或者reload)的时候,会立即执行模块文件的顶层程序代码(不在函数内的代码,比如变量x'=Gx',函数定义def f1等,只要顶格写都会被执行),而位于函数主体内的代码直到函数被调用后才会执行,所以f1(x,y,z)函数被调用了,打印出了"Ex Gy Ez",而f1又自己调用了f2,所以f2函数打印了"Lx Gy Ez"
那么,既然模块有导入成功,x变量应该有定义,为何又提示“name 'x' is not defined”呢?
这是因为:为了避免大家的相同编程习惯导致各种变量覆盖(比如张三和李四被分派写两个不同的模块,张三习惯在他的变量中使用x,李四也习惯这样,那么当两个模块都被导入时,因为变量名相同,必然有一个的值会被覆盖掉),于是python在导入模块时,以模块名新建一个新的名称空间,在新的名称空间中创建变量。 简单地说,当导入getvalue模块的x变量的时候,此时x不再被当成x,而是被当成getvalue.x
例子:(接上例)
[root@cqhdtest python_learn]# cat index.py import getvalue print getvalue.x [root@cqhdtest python_learn]# python index.py Ex Gy Ez Lx Gy Ez Gx
可以看见,此时的print 语句已经可以正常输出。
那么,如果我想随时随地可以导入getvalue模块,而又不想切到指定路径去,那么该怎么办呢?
这个时候,就要用到sys.path这个变量了
例子:
In [2]: import sys In [3]: sys.path Out[3]: ['', '/usr/local/anaconda2/bin', '/usr/local/anaconda2/lib/python27.zip', '/usr/local/anaconda2/lib/python2.7', '/usr/local/anaconda2/lib/python2.7/plat-linux2', '/usr/local/anaconda2/lib/python2.7/lib-tk', '/usr/local/anaconda2/lib/python2.7/lib-old', '/usr/local/anaconda2/lib/python2.7/lib-dynload', '/usr/local/anaconda2/lib/python2.7/site-packages', '/usr/local/anaconda2/lib/python2.7/site-packages/IPython/extensions', '/root/.ipython'] In [4]: sys.path.insert('/root/python_learn/') --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-4-b628fd39dcd4> in <module>() ----> 1 sys.path.insert('/root/python_learn/') TypeError: insert() takes exactly 2 arguments (1 given) In [5]: help (list.insert) In [6]: sys.path.insert(,'/root/python_learn/') File "<ipython-input-6-c98c91c9451b>", line 1 sys.path.insert(,'/root/python_learn/') ^ SyntaxError: invalid syntax In [7]: sys.path.insert(0,'/root/python_learn/') In [8]: sys.path Out[8]: ['/root/python_learn/', '', '/usr/local/anaconda2/bin', '/usr/local/anaconda2/lib/python27.zip', '/usr/local/anaconda2/lib/python2.7', '/usr/local/anaconda2/lib/python2.7/plat-linux2', '/usr/local/anaconda2/lib/python2.7/lib-tk', '/usr/local/anaconda2/lib/python2.7/lib-old', '/usr/local/anaconda2/lib/python2.7/lib-dynload', '/usr/local/anaconda2/lib/python2.7/site-packages', '/usr/local/anaconda2/lib/python2.7/site-packages/IPython/extensions', '/root/.ipython'] In [9]: import getvalue Ex Gy Ez Lx Gy Ez In [10]: getvalue.x Out[10]: 'Gx'
python按照sys.path的顺序来查找模块,需要注意的是,insert方法需要两个参数,第一个是索引,这里使用0,放在第一位,优先查找我们自己的目录
如果我们再次import,python并不会再次执行顶层程序代码,而是简单地重载下内存中的对象
例子:
In [29]: import getvalue In [30]: getvalue reload File "<ipython-input-30-7cba10969034>", line 1 getvalue reload ^ SyntaxError: invalid syntax In [31]: help(reload) In [32]: reload(getvalue) Ex Gy Ez Lx Gy Ez Out[32]: <module 'getvalue' from '/root/python_learn/getvalue.pyc'>
现在,模块加载没什么问题了,但是我觉得每次都要敲完整模块名getvalue,太烦人了,有没有什么办法呢?
这个时候就要用到import-as语句了
例子:
In [33]: import getvalue as g In [34]: g.x Out[34]: 'Gx'
import xx as x:把本来先创建名称空间名为getvlaue改成了g,所以调用就简单了,因为是修改所以此时getvalue这个名称空间是不存在的,所以不能用getvalue+'.'获取值
那么如果我比较任性,就想覆盖当前环境中的变量x呢?
这个时候就得用到from-import 语句了
例子:
In [35]: from getvalue import x In [36]: x Out[36]: 'Gx'
from-import语句只会加载对应的属性或者方法到当前的名称空间,所以其他语句不会执行
所以python导入模块,大概分成以下几类:
import:直接导入
import Module as Module_alias:给变量取别名
from Module import Attribute/Method: 导入部分属性/方法
reload(Module):重新导入
既然作为模块,就该有作为模块的觉悟,一导入就瞎执行是会被clear的-_-!!
所以我们不该让模块中包含不该执行的语句,比如函数不该被调用。但是我又想这个模块文件有时作为程序顶层文件执行,有时作为模块被导入,那么有办法吗?
这个时候就可以用到内置属性__name__了
例子:
[root@cqhdtest python_learn]# cp getvalue.py New.py [root@cqhdtest python_learn]# vi New.py [root@cqhdtest python_learn]# cat New.py #!/usr/local/anaconda2/bin/python x='Gx' y='Gy' z='Gz' def f1(x,y,z): x='Ex' z='Ez' print x,y,z def f2(x,y,z): x='Lx' print x,y,z f2(x,y,z) if __name__ == "__main__" : f1(x,y,z) [root@cqhdtest python_learn]# python New.py Ex Gy Ez Lx Gy Ez ============================================ In [6]: import New In [7]: New.x Out[7]: 'Gx' In [8]: reload(New) Out[8]: <module 'New' from 'New.pyc'> In [9]: New.__name__ Out[9]: 'New'
这里的内置变量__name__,如果程序是顶层文件则为"__main__",否则为模块名
2.import的工作机制(摘抄自:https://www.cnblogs.com/bobo0609/p/6938012.html)
import语句导入指定的模块时会执行3个步骤
1. 找到模块文件:在模块搜索路径下搜索模块文件
程序的主目录
PYTHONPATH目录
标准链接库目录
2.编译成字节码:文件导入时会编译,因此,顶层文件的.pyc字节码文件在内部使用后会被丢弃,只有被导入的文件才会留下.pyc文件
3.执行模块的代码来创建其所定义的对象:模块文件中的所有语句从头至尾依次执行,而此步骤中任何对变量名的赋值运算,都会产生所得到的模块文件的属性
注意:模块只在第一次导入时才会执行如上步骤,后续的导入操作只不过是提取内存中已加载的模块对象,reload()可用于重新加载模块
包: 用于将一组模块归并到一个目录中,此目录即为包,目录名即为包名
包是一个有层次的文件目录结构,它定义了一个由模块和子包组成的Python应用执行环境
基于包,Python在执行模块导入时可以指定模块的导入路径 import pack1.pack2.mod1
每个包内都必须有__init__.py文件, __init__.py 可包含python代码,但通常为空,仅用于扮演包初始化、替目录产生模块命名空间以及使用目录导入时实现from*行为的角色
标签:python 模块
原文地址:http://blog.51cto.com/linzb/2090261