欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

python模塊導(dǎo)入的細(xì)節(jié)詳解

 更新時(shí)間:2018年12月10日 11:38:20   作者:駿馬金龍  
這篇文章主要給大家介紹了關(guān)于python模塊導(dǎo)入細(xì)節(jié)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

python模塊導(dǎo)入細(xì)節(jié)

本文主要介紹了關(guān)于python模塊導(dǎo)入的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細(xì)的介紹吧

官方手冊(cè):https://docs.python.org/3/tutorial/modules.html

可執(zhí)行文件和模塊

python源代碼文件按照功能可以分為兩種類型:

  • 用于執(zhí)行的可執(zhí)行程序文件
  • 不用與執(zhí)行,僅用于被其它python源碼文件導(dǎo)入的模塊文件

例如文件a.py和b.py在同一目錄下,它們的內(nèi)容分別是:

# b.py
x="var x in module b"
y=5

# a.py:
import b
import sys
print(b.x)
print(b.y)

a.py導(dǎo)入其它文件(b.py)后,就可以使用b.py文件中的屬性(如變量、函數(shù)等)。這里,a.py就是可執(zhí)行文件,b.py就是模塊文件,但模塊名為b,而非b.py。

python提供了一些標(biāo)準(zhǔn)庫(kù),是預(yù)定義好的模塊文件,例如上面的sys模塊。

在此有幾個(gè)注意點(diǎn),在后面會(huì)詳細(xì)解釋:

  1. 模塊b的文件名為b.py,但import導(dǎo)入的時(shí)候,使用的名稱為b,而非b.py
  2. a.py和b.py是在同一個(gè)目錄下的,如果不在同目錄下能否導(dǎo)入?
  3. 在a.py中訪問b.py模塊中的屬性時(shí),使用的是b.x、b.y
  4. 上面都是直接以模塊名導(dǎo)入的,python還支持更復(fù)雜的包導(dǎo)入方式,例如導(dǎo)入abc/b.py時(shí),使用import abc.b。下一篇文章會(huì)詳細(xì)解釋包的導(dǎo)入方式

python模塊搜索路徑

在a.py中導(dǎo)入模塊b的時(shí)候,python會(huì)做一系列的模塊文件路徑搜索操作:b.py在哪里?只有找到它才能讀取、運(yùn)行(裝載)該模塊。

在任何一個(gè)python程序啟動(dòng)時(shí),都會(huì)將模塊的搜索路徑收集到sys模塊的path屬性中(sys.path)。當(dāng)python需要搜索模塊文件在何處時(shí),首先搜索內(nèi)置模塊,如果不是內(nèi)置模塊,則搜索sys.path中的路徑列表,搜索時(shí)會(huì)從該屬性列出的路徑中按照從前向后的順序進(jìn)行搜索,并且只要找到就立即停止搜索該模塊文件(也就是說不會(huì)后搜索的同名模塊覆蓋先搜索的同名模塊)。

例如,在a.py文件中輸出一下這個(gè)屬性的內(nèi)容:

# a.py:
import sys
print(sys.path)

結(jié)果:

['G:\\pycode', 'C:\\Program Files (x86)\\Python36-32\\python36.zip', 'C:\\Program Files (x86)\\Python36-32\\DLLs', 'C:\\Program Files (x86)\\Python36-32\\lib', 'C:\\Program Files (x86)\\Python36-32', 'C:\\Users\\malong\\AppData\\Roaming\\Python\\Python36\\site-packages', 'C:\\Program Files (x86)\\Python36-32\\lib\\site-packages']

python模塊的搜索路徑包括幾個(gè)方面,按照如下順序搜索:

  • 程序文件(a.py)所在目錄,即G:\\pycode
  • 環(huán)境變量PYTHONPATH所設(shè)置的路徑(如果定義了該環(huán)境變量,則從左向右的順序搜索)
  • 標(biāo)準(zhǔn)庫(kù)路徑
  • .pth文件中定義的路徑

需要注意,上面sys.path的結(jié)果中,除了.zip是一個(gè)文件外,其它的搜索路徑全都是目錄,也就是從這些目錄中搜索模塊X的文件X.py是否存在。

程序所在目錄

這個(gè)目錄是最先搜索的,且是python自動(dòng)搜索的,無需對(duì)此進(jìn)行任何設(shè)置。從交互式python程序終輸出sys.path的結(jié)果:

>>> sys.path
['', 'C:\\WINDOWS\\system32', 'C:\\Program Files (x86)\\Python36-32\\Lib\\idlelib', 'C:\\Program Files (x86)\\Python36-32\\python36.zip', 'C:\\Program Files (x86)\\Python36-32\\DLLs', 'C:\\Program Files (x86)\\Python36-32\\lib', 'C:\\Program Files (x86)\\Python36-32', 'C:\\Users\\malong\\AppData\\Roaming\\Python\\Python36\\site-packages', 'C:\\Program Files (x86)\\Python36-32\\lib\\site-packages']

其中第一個(gè)''表示的就是程序所在目錄。

注意程序所在目錄和當(dāng)前目錄是不同的。例如,在/tmp/目錄下執(zhí)行/pycode中的a.py文件

cd /tmp
python /pycode/a.py

其中/tmp為當(dāng)前目錄,而/pycode是程序文件a.py所在的目錄。如果a.py中導(dǎo)入b.py,那么將首先搜索/pycode,而不是/tmp。

環(huán)境變量PYTHONPATH

這個(gè)變量中可以自定義一系列的模塊搜索路徑列表,這樣可以跨目錄搜索(另一種方式是設(shè)置.pth文件)。但默認(rèn)情況下這個(gè)環(huán)境變量是未設(shè)置的。

在windows下,設(shè)置PYTHONPATH環(huán)境變量的方式:命令行中輸入:SystemPropertiesAdvanced-->環(huán)境變量-->系統(tǒng)環(huán)境變量新建

如果是多個(gè)路徑,則使用英文格式的分號(hào)分隔。以下是臨時(shí)設(shè)置當(dāng)前命令行窗口的PYTHONPATH:

set PYTHONPATH='D:\pypath; d:\pypath1'

在unix下,設(shè)置PYTHONPATH環(huán)境變量的方式,使用冒號(hào)分隔多個(gè)路徑:另外,必須得export導(dǎo)出為環(huán)境變量

export PYTHONPATH=/tmp/pypath1:/tmp/pypath2

如果要永久生效,則寫入配置文件中:

echo 'export PYTHONPATH=/tmp/pypath1:/tmp/pypath2' >/etc/profile.d/pypth.sh
chmod +x /etc/profile.d/pypth.sh
source /etc/profile.d/pypth.sh

標(biāo)準(zhǔn)庫(kù)路徑

在Linux下,標(biāo)準(zhǔn)庫(kù)的路徑一般是在/usr/lib/pythonXXX/下(XXX表示python版本號(hào)),此目錄下有些分了子目錄。

例如:

['', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']

其中/usr/lib/python3.5和其內(nèi)的幾個(gè)子目錄都是標(biāo)準(zhǔn)庫(kù)的搜索路徑。

注意其中/usr/lib/python35.zip,它是ZIP文件組件,當(dāng)定義此文件為搜索路徑時(shí),將自動(dòng)解壓縮該文件,并從此文件中搜索模塊。

Windows下根據(jù)python安裝位置的不同,標(biāo)準(zhǔn)庫(kù)的路徑不同。如果以默認(rèn)路徑方式安裝的python,則標(biāo)準(zhǔn)庫(kù)路徑為C:\\Program Files (x86)\\Python36-32及其分類的子目錄。

.pth文件自定義路徑

可以將自定義的搜索路徑放進(jìn)一個(gè).pth文件中,每行一個(gè)搜索路徑。然后將.pth文件放在python安裝目錄或某個(gè)標(biāo)準(zhǔn)庫(kù)路徑內(nèi)的sitepackages目錄下即可。

這是一種替換PYTHONPATH的友好方式,因?yàn)椴煌僮飨到y(tǒng)設(shè)置環(huán)境變量的方式不一樣,而以文件的方式記錄是所有操作系統(tǒng)都通用的。

例如,windows下,在python安裝目錄C:\\Program Files (x86)\\Python36-32下新增一個(gè)mypath.pth文件,內(nèi)容如下:

d:\pypath1
d:\pypath2

再去輸出sys.path,將可以看到這兩個(gè)路徑已經(jīng)放進(jìn)了搜索列表中。

修改搜索路徑

除了上面環(huán)境變量和.pth文件,還可以直接修改sys.path或者site.getsitepackages()的結(jié)果。

例如,在import導(dǎo)入sys模塊之后,可以修改sys.path,向這個(gè)列表中添加其它搜索路徑,這樣之后導(dǎo)入其它模塊的時(shí)候,也會(huì)搜索該路徑。

例如:

import sys
sys.path.append('d:\\pypath3')
print(sys.path)

sys.path的最后一項(xiàng)將是新添加的路徑。

導(dǎo)入模塊的細(xì)節(jié)

導(dǎo)入模塊時(shí)的過程

python的import是在程序運(yùn)行期間執(zhí)行的,并非像其它很多語(yǔ)言一樣是在編譯期間執(zhí)行。也就是說,import可以出現(xiàn)在任何地方,只有執(zhí)行到這個(gè)import行時(shí),才會(huì)執(zhí)行導(dǎo)入操作。且在import某個(gè)模塊之前,無法訪問這個(gè)模塊的屬性。

python在import導(dǎo)入模塊時(shí),首先搜索模塊的路徑,然后編譯并執(zhí)行這個(gè)模塊文件。雖然概括起來只有兩個(gè)過程,但實(shí)際上很復(fù)雜。

前文已經(jīng)解釋了import的模塊搜索過程,所以這里大概介紹import的其它細(xì)節(jié)。

以前面的a.py中導(dǎo)入模塊文件b.py為例:

import b

import導(dǎo)入模塊時(shí),搜索到模塊文件b.py后:

1.首先在內(nèi)存中為每個(gè)待導(dǎo)入的模塊構(gòu)建module類的實(shí)例:模塊對(duì)象。這個(gè)模塊對(duì)象目前是空對(duì)象,這個(gè)對(duì)象的名稱為全局變量b。

注意細(xì)節(jié):module類的對(duì)象,變量b。

輸出下它們就知道:

print(b)
print(type(b))

輸出結(jié)果:

<module 'b' from 'g:\\pycode\\b.py'>
<class 'module'>

因?yàn)閎是全局變量,所以當(dāng)前程序文件a.py中不能重新對(duì)全局變量b進(jìn)行賦值,這會(huì)使導(dǎo)入的模塊b被丟棄。例如,下面是錯(cuò)誤的:

import b
b=3
print(b.x) # 已經(jīng)沒有模塊b了

另外,因?yàn)閕mport導(dǎo)入時(shí)是將模塊對(duì)象賦值給模塊變量,所以模塊變量名不能是python中的一些關(guān)鍵字,比如if、for等,這時(shí)會(huì)報(bào)錯(cuò)。雖然模塊文件名可以為list、keys等這樣的內(nèi)置函數(shù)名,但這會(huì)導(dǎo)致這些內(nèi)置函數(shù)不可用,因?yàn)楦鶕?jù)變量查找的作用域規(guī)則,首先查找全局變量,再查找內(nèi)置作用域。也就是說,模塊文件的文件名不能是這些關(guān)鍵字、也不應(yīng)該是這些內(nèi)置函數(shù)名。

 File "g:/pycode/new.py", line 11
 import if
 ^
SyntaxError: invalid syntax

2.構(gòu)造空模塊實(shí)例后,將編譯、執(zhí)行模塊文件b.py,并按照一定的規(guī)則將一些結(jié)果放進(jìn)這個(gè)模塊對(duì)象中。

注意細(xì)節(jié),編譯、執(zhí)行b.py、將結(jié)果保存到模塊對(duì)象中。

模塊第一次被導(dǎo)入的時(shí)候,會(huì)進(jìn)行編譯,并生成.pyc字節(jié)碼文件,然后python執(zhí)行這個(gè)pyc文件。當(dāng)模塊被再次導(dǎo)入時(shí),如果檢查到pyc文件的存在,且和源代碼文件的上一次修改時(shí)間戳mtime完全對(duì)應(yīng)(也就是說,編譯后源代碼沒有進(jìn)行過修改),則直接裝載這個(gè)pyc文件并執(zhí)行,不會(huì)再進(jìn)行額外的編譯過程。當(dāng)然,如果修改過源代碼,將會(huì)重新編譯得到新的pyc文件。

注意,并非所有的py文件都會(huì)生成編譯得到的pyc文件,對(duì)于那些只執(zhí)行一次的程序文件,會(huì)將內(nèi)存中的編譯結(jié)果在執(zhí)行完成后直接丟棄(多數(shù)時(shí)候如此,但仍有例外,比如使用compileall模塊可以強(qiáng)制編譯成pyc文件),但模塊會(huì)將內(nèi)存中的編譯結(jié)果持久化到pyc文件中。另外,運(yùn)行字節(jié)碼pyc文件并不會(huì)比直接運(yùn)行py文件更快,執(zhí)行它也一樣是一行行地解釋、執(zhí)行,唯一快的地方在于導(dǎo)入裝載的時(shí)候無需重新編譯而已。

執(zhí)行模塊文件(已完成編譯)的時(shí)候,按照一般的執(zhí)行流程執(zhí)行:一行一行地、以代碼塊為單元執(zhí)行。一般地,模塊文件中只用來聲明變量、函數(shù)等屬性,以便提供給導(dǎo)入它的模塊使用,而不應(yīng)該有其他任何操作性的行為,比如print()操作不應(yīng)該出現(xiàn)在模塊文件中,但這并非強(qiáng)制。

總之,執(zhí)行完模塊文件后,這個(gè)模塊文件將有一個(gè)自己的全局名稱空間,在此模塊文件中定義的變量、函數(shù)等屬性,都會(huì)記錄在此名稱空間中。

最后,模塊的這些屬性都會(huì)保存到模塊對(duì)象中。由于這個(gè)模塊對(duì)象賦值給了模塊變量b,所以通過變量b可以訪問到這個(gè)對(duì)象中的屬性(比如變量、函數(shù)等),也就是模塊文件內(nèi)定義的全局屬性。

只導(dǎo)入一次

假設(shè)a.py中導(dǎo)入了模塊b和模塊sys,在b.py中也導(dǎo)入了模塊sys,但python默認(rèn)對(duì)某個(gè)模塊只會(huì)導(dǎo)入一次,如果a.py中先導(dǎo)入sys,再導(dǎo)入b,那么導(dǎo)入b并執(zhí)行b.py的時(shí)候,會(huì)發(fā)現(xiàn)sys已經(jīng)導(dǎo)入了,不會(huì)再去導(dǎo)入sys。

實(shí)際上,python執(zhí)行程序的時(shí)候,會(huì)將所有已經(jīng)導(dǎo)入的模塊放進(jìn)sys.module屬性中,這是一個(gè)dict,可以通過下面的方式查看已導(dǎo)入的模塊名:

>>> import sys
>>> list(sys.module.keys())

如果某個(gè)程序文件中多次使用import(或from)導(dǎo)入同一個(gè)模塊,雖然不會(huì)報(bào)錯(cuò),但實(shí)際上還是直接使用內(nèi)存中已裝載好的模塊對(duì)象。

例如,b.py中x=3,導(dǎo)入它之后修改該值,然后再次導(dǎo)入,發(fā)現(xiàn)b.x并不會(huì)發(fā)生改變:

import b
print(b.x) # 3

b.x=33
print(b.x) # 33

import b 
print(b.x) # 33

但是python提供了reload進(jìn)行多次重復(fù)導(dǎo)入的方法,見后文。

使用別名

import導(dǎo)入時(shí),可以使用as關(guān)鍵字指定一個(gè)別名作為模塊對(duì)象的變量,例如:

import b as bb
bb.x=3
print(bb.x)

這時(shí)候模塊對(duì)象將賦值給變量bb,而不是b,b此時(shí)不再是模塊對(duì)象變量,而僅僅只是模塊名。使用別名并不會(huì)影響性能,因?yàn)樗鼉H僅只是一個(gè)賦值過程,只不過是從原來的賦值對(duì)象變量b變?yōu)樽兞縝b而已。

from導(dǎo)入部分屬性

import語(yǔ)句是導(dǎo)入模塊中的所有屬性,并且訪問時(shí)需要使用模塊變量來引用。例如:

import b
print(b.x)

除了import,還有一個(gè)from語(yǔ)句,表示從模塊中導(dǎo)入部分指定的屬性,且使得可以直接使用這些屬性的名稱來引用這些屬性,而不需要加上模塊變量名。例如原來import導(dǎo)入時(shí)訪問變量x使用b.x,from導(dǎo)入時(shí)只需使用x即可。實(shí)際上,from導(dǎo)入更應(yīng)該稱為屬性的再次賦值(拷貝)。

例如,b.py中定義了變量x、y、z,同時(shí)定義了函數(shù)f()和g(),在a.py中導(dǎo)入這個(gè)模塊文件,但只導(dǎo)入x變量和f函數(shù):

# a.py文件內(nèi)容:
from b import x,f

print(x)
f()

# b.py文件內(nèi)容:
x=3
y=4
z=5
def f():
 print("function f in b.py")

def g():
 print("function g in b.py")

注意上面a.py中引用模塊b中屬性的方式?jīng)]有加上b.X,而是直接使用x和f()來引用。這和import是不一樣的。至于from和import導(dǎo)入時(shí)的變量名稱細(xì)節(jié),在下面的內(nèi)容中會(huì)詳細(xì)解釋。

雖然from語(yǔ)句只導(dǎo)入模塊的部分屬性,但實(shí)際上仍然會(huì)完整地執(zhí)行整個(gè)模塊文件。

同樣的,from語(yǔ)句也可以指定導(dǎo)入屬性的變量別名,例如,將b.py中的屬性x賦值給xx,將y賦值給yy:

from b import x as xx,y as yy
print(xx)
print(yy)

from語(yǔ)句還有一個(gè)特殊導(dǎo)入統(tǒng)配符號(hào)*,它表示導(dǎo)入模塊中的所有屬性。

# a.py文件:
from b import *
print(x,y,z)
f()
g()

多數(shù)時(shí)候,不應(yīng)該使用from *的方式,因?yàn)槲覀兛赡軙?huì)忘記某個(gè)模塊中有哪些屬性拷貝到了當(dāng)前文件,特別是多個(gè)from *時(shí)可能會(huì)出現(xiàn)屬性覆蓋的問題。

重載模塊:imp.reload()

無論時(shí)import還是from,都只導(dǎo)入一次模塊,但使用reload()可以強(qiáng)制重新裝載模塊。

reload()是imp模塊中的一個(gè)函數(shù),所以要使用imp.reload()之前,必須先導(dǎo)入imp。

from imp import reload
reload(b)

reload()是一個(gè)函數(shù),它的參數(shù)是一個(gè)已經(jīng)成功被導(dǎo)入過的模塊變量(如果使用了別名,則應(yīng)該使用別名作為reload的參數(shù)),也就是說該模塊必須在內(nèi)存中已經(jīng)有自己的模塊對(duì)象。

reload()會(huì)重新執(zhí)行模塊文件,并將執(zhí)行得到的屬性完全覆蓋到原有的模塊對(duì)象中。也就是說,reload()會(huì)重新執(zhí)行模塊文件,但不會(huì)在內(nèi)存中建立新的模塊對(duì)象,所以原有模塊對(duì)象中的屬性可能會(huì)被修改。

例如,模塊文件b.py中x=3,導(dǎo)入b模塊,修改其值為33,然后reload這個(gè)模塊,會(huì)發(fā)現(xiàn)值重新變回了3。

import b
print(b.x) # 3

b.x=33
print(b.x) # 33

from imp import reload
reload(b)

print(b.x) # 3

有時(shí)候reload()很有用,可以讓程序無需重啟就執(zhí)行新的代碼。例如,在python的交互式模式下導(dǎo)入模塊b,然后修改python源碼,再reload導(dǎo)入:

>>> import b
>>> b.x
3

# 不要關(guān)掉交互式解釋器,直接修改源代碼中的b=3333

>>> from imp import reload
>>> reload(b)
<module 'b' from 'G:\\pycode\\b.py'>
>>> b.x
3333

但正因?yàn)閞eload()重載模塊會(huì)改變?cè)嫉闹担@可能是很危險(xiǎn)的行為,一定要清楚地知道它是在干什么。

導(dǎo)入模塊時(shí)的變量名稱細(xì)節(jié)

import導(dǎo)入的變量

import導(dǎo)入時(shí),模塊對(duì)象中的屬性有自己的名稱空間,然后將整個(gè)模塊對(duì)象賦值給模塊變量。

例如,在a.py中導(dǎo)入b:

import b
print(b.x)

這個(gè)過程唯一和當(dāng)前文件a.py作用域有關(guān)的就是模塊對(duì)象變量b,b.py中聲明的屬性和當(dāng)前文件無任何關(guān)系。無論是訪問還是修改,都是直接修改這個(gè)模塊對(duì)象自身作用域中的值。所以,只要模塊變量b不出現(xiàn)沖突問題,可以放心地修改模塊b中的屬性。

另一方面,因?yàn)槊總€(gè)進(jìn)程都有自己的內(nèi)存空間,所以在a.py、c.py中都導(dǎo)入b時(shí),a.py中修改b的屬性值不會(huì)影響c.py中導(dǎo)入的屬性,a.py和c.py中模塊對(duì)象所保存的屬性都是執(zhí)行b.py后得到的,它們相互獨(dú)立。

from導(dǎo)入的變量

from導(dǎo)入模塊時(shí),會(huì)先執(zhí)行完模塊文件,然后將指定的部分屬性重新賦值給當(dāng)前程序文件的同名全局變量。

例如,在模塊文件b.py中定義了x、y、z變量和f()、g()函數(shù):

# b.py:
x=3
y=4
b=5
def f():
 print("function f in b.py")

def g():
 print("function g in b.py")

當(dāng)在a.py中導(dǎo)入b模塊時(shí),如果只導(dǎo)入x、y和f():

# a.py:
from b import x, y, f

實(shí)際上的行為是構(gòu)造模塊對(duì)象后,將這個(gè)模塊對(duì)象對(duì)應(yīng)的名稱空間中的屬性x、y和f重新賦值給a.py中的變量x、y和f,然后丟棄整個(gè)模塊對(duì)象以及整個(gè)名稱空間。換句話說,b不再是一個(gè)有效的模塊變量(所以和import不一樣),來自b的x,y,z,f和g也都被丟棄。

這里有幾個(gè)細(xì)節(jié),需要詳細(xì)解釋清楚,只有理解了才能搞清楚它們是怎么生效的。

假設(shè)現(xiàn)在模塊文件b.py的內(nèi)容為,并且a.py中導(dǎo)入x,y,f屬性:

# b.py:
x=3
y=[1,2]
z=5
def f():
 print("function f in b.py")

def g():
 print("function g in b.py")

# a.py:
from b import x,y,f

首先在執(zhí)行模塊文件b.py時(shí),會(huì)構(gòu)造好自己的模塊對(duì)象,并且模塊對(duì)象有自己的名稱空間(作用域),模塊對(duì)象構(gòu)造完成后,它的名稱空間大致如下:

然后python會(huì)在a.py的全局作用域內(nèi)創(chuàng)建和導(dǎo)入屬性同名的全局變量x,y和f,并且通過賦值的方式將模塊的屬性賦值給這些全局變量,也就是:

x = b.x
y = b.y
f = b.f

上面的b只是用來演示,實(shí)際上變量b是不存在的。

賦值完成后,我們和構(gòu)造的整個(gè)模塊對(duì)象就失去聯(lián)系了,因?yàn)闆]有變量b去引用這個(gè)對(duì)象。但需要注意,這個(gè)對(duì)象并沒有被刪除,僅僅只是我們無法通過b去找到它。

所以,現(xiàn)在的示意圖如下:

因?yàn)槭琴x值的方式傳值的,所以在a.py中修改這幾個(gè)變量的值時(shí),是直接在模塊對(duì)象作用域內(nèi)修改的:對(duì)于不可變對(duì)象,將在此作用域內(nèi)創(chuàng)建新對(duì)象,對(duì)于可變對(duì)象,將直接修改原始對(duì)象的值。

另一方面,由于模塊對(duì)象一直保留在內(nèi)存中,下次繼續(xù)導(dǎo)入時(shí),將直接使用該模塊對(duì)象。對(duì)于import和from,是直接使用該已存在的模塊對(duì)象,對(duì)于reload,是覆蓋此模塊對(duì)象。

例如,在a.py中修改不可變對(duì)象x和可變對(duì)象y,之后import或from時(shí),可變對(duì)象的值都會(huì)隨之改變,因?yàn)樗鼈兪褂玫亩际窃瓉淼哪K對(duì)象:

from b import x,y

x=33
y[0]=333

from b import x,y
print((x,y)) # 輸出(3, [333, 2])

import b
print((b.x,b.y)) # 輸出(3, [333, 2])

from導(dǎo)入時(shí),由于b不再是模塊變量,所以無法再使用reload(b)去重載對(duì)象。如果想要重載,只能先import,再reload:

from b import x,y
...CODE...

# 想要重載b
import b
from imp import reload
reload(b)

查看模塊中的屬性

內(nèi)置函數(shù)dir可用于列出某模塊中定義了哪些屬性(全局名稱空間)。完整的說明見help(dir)。

import b
dir(b)

輸出結(jié)果:

['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'f', 'g', 'x', 'y', 'z']

可見,模塊的屬性中除了自己定義的屬性外,還有一些內(nèi)置的屬性,比如上面以__開頭和結(jié)尾的屬性。

如果dir()不給任何參數(shù),則輸出當(dāng)前環(huán)境下定義的名稱屬性:

>>> import b
>>> x=3
>>> aaa=333
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'aaa', 'b', 'x']

每個(gè)屬性都對(duì)應(yīng)一個(gè)對(duì)象,例如x對(duì)應(yīng)的是int對(duì)象,b對(duì)應(yīng)的是module對(duì)象:

>>> type(x)
<class 'int'>
>>> type(b)
<class 'module'>

既然是對(duì)象,那么它們都會(huì)有自己的屬性。例如:

>>> dir(x)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

所以,也可以直接dir某個(gè)模塊內(nèi)的屬性:

import b
dir(b.x)
dir(b.__name__)

dir()不會(huì)列出內(nèi)置的函數(shù)和變量,如果想要輸出內(nèi)置的函數(shù)和變量,可以去標(biāo)準(zhǔn)模塊builtins中查看,因?yàn)樗鼈兌x在此模塊中:

import builtins
dir(buildins)

除了內(nèi)置dir()函數(shù)可以獲取屬性列表(名稱空間),對(duì)象的__dict__屬性也可以獲取對(duì)象的屬性字典(名稱空間),它們的結(jié)果不完全一樣。詳細(xì)說明參見dir()和__dict__屬性區(qū)別。

總的來說,獲取對(duì)象M中一個(gè)自定義的屬性age,有以下幾種方法:

M.age
M.__dict__['age']
sys.modules['M'].age
getattr(M,'age')

有妙用的__name__屬性

前面說了,py文件分兩種:用于執(zhí)行的程序文件和用于導(dǎo)入的模塊文件。當(dāng)直接使用python a.py的時(shí)候表示a.py是用于執(zhí)行的程序文件,通過import/from方式導(dǎo)入的py文件是模塊文件。

__name__屬性用來區(qū)分py文件是程序文件還是模塊文件:

  • 當(dāng)文件是程序文件的時(shí)候,該屬性被設(shè)置為__main__
  • 當(dāng)文件是模塊文件的時(shí)候(也就是被導(dǎo)入時(shí)),該屬性被設(shè)置為自身模塊名

換句話說,__main__表示的是當(dāng)前執(zhí)行程序文件的默認(rèn)模塊名,想必學(xué)過其他支持包功能的語(yǔ)言的人很容易理解:程序都需要一個(gè)入口,入口程序所在的包就是main包,在main包中導(dǎo)入其它包來組織整個(gè)程序。python也是如此,只不過它是隱式自動(dòng)設(shè)置的。

對(duì)于python來說,因?yàn)殡[式自動(dòng)設(shè)置,該屬性就有了特殊妙用:直接在模塊文件中通過if __name__ == "__main__"來判斷,然后寫屬于執(zhí)行程序的代碼,如果直接用python執(zhí)行這個(gè)文件,說明這個(gè)文件是程序文件,于是會(huì)執(zhí)行屬于if代碼塊的代碼,如果是被導(dǎo)入,則是模塊文件,if代碼塊中的代碼不會(huì)被執(zhí)行。

顯然,這是python中非常方便的單元測(cè)試方式。

例如,寫一個(gè)模塊文件,里面包含一個(gè)函數(shù),用來求給定序列的最大值和最小值:

def minmax(func,*args):
 res = args[0]
 for arg in args[1:]:
  if func(arg,res):
   res = arg
 return res

def lessthan(x,y): return x < y
def greatethan(x,y): return x > y

# 測(cè)試代碼
if __name__ == "__main__":
 print(minmax(lessthan,3,6,2,1,4,5))
 print(minmax(greatethan,3,6,2,1,4,5))

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • python性能測(cè)量工具cProfile使用解析

    python性能測(cè)量工具cProfile使用解析

    這篇文章主要介紹了python性能測(cè)量工具cProfile使用解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Django ModelSerializer實(shí)現(xiàn)自定義驗(yàn)證的使用示例

    Django ModelSerializer實(shí)現(xiàn)自定義驗(yàn)證的使用示例

    本文主要介紹了Django ModelSerializer實(shí)現(xiàn)自定義驗(yàn)證的使用示例,多種字段驗(yàn)證器幫助開發(fā)者確保數(shù)據(jù)的完整性和準(zhǔn)確性,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-11-11
  • PyQt4編程之讓狀態(tài)欄顯示信息的方法

    PyQt4編程之讓狀態(tài)欄顯示信息的方法

    今天小編就為大家分享一篇PyQt4編程之讓狀態(tài)欄顯示信息的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • python神經(jīng)網(wǎng)絡(luò)ResNet50模型的復(fù)現(xiàn)詳解

    python神經(jīng)網(wǎng)絡(luò)ResNet50模型的復(fù)現(xiàn)詳解

    這篇文章主要為大家介紹了python神經(jīng)網(wǎng)絡(luò)ResNet50模型的復(fù)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Python Pandas數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)單介紹

    Python Pandas數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)單介紹

    這篇文章主要介紹了Python Pandas數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)單介紹的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • Django中常遇到的錯(cuò)誤問題

    Django中常遇到的錯(cuò)誤問題

    在Django開發(fā)中,設(shè)置DEBUG=False時(shí)需要配置ALLOWED_HOSTS以防止報(bào)錯(cuò),此外,如果django-admin.py命令找不到,需添加Django的安裝路徑到系統(tǒng)環(huán)境變量,此文還提供了一些常見Django錯(cuò)誤的解決方法,如數(shù)據(jù)庫(kù)添加中文報(bào)錯(cuò)、信號(hào)無法觸發(fā)等問題
    2024-09-09
  • 決策樹剪枝算法的python實(shí)現(xiàn)方法詳解

    決策樹剪枝算法的python實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了決策樹剪枝算法的python實(shí)現(xiàn)方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了決策樹剪枝算法的概念、原理并結(jié)合實(shí)例形式分析了Python相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2019-09-09
  • python實(shí)現(xiàn)的解析crontab配置文件代碼

    python實(shí)現(xiàn)的解析crontab配置文件代碼

    這篇文章主要介紹了python實(shí)現(xiàn)的解析crontab配置文件代碼,也可以說是python版的crontab,代碼中包含大量注釋,需要的朋友可以參考下
    2014-06-06
  • 解決python大批量讀寫.doc文件的問題

    解決python大批量讀寫.doc文件的問題

    今天小編就為大家分享一篇解決python大批量讀寫.doc文件的問題。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • Python實(shí)現(xiàn)CAN報(bào)文轉(zhuǎn)換工具教程

    Python實(shí)現(xiàn)CAN報(bào)文轉(zhuǎn)換工具教程

    這篇文章主要介紹了Python實(shí)現(xiàn)CAN報(bào)文轉(zhuǎn)換工具教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05

最新評(píng)論