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*行爲的角色


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章