1. 程式人生 > >python模組學習

python模組學習

import 語句

想使用 Python 原始檔,只需在另一個原始檔裡執行 import 語句,語法如下:

import module1[, module2[,... moduleN]

當直譯器遇到 import 語句,如果模組在當前的搜尋路徑就會被匯入。

搜尋路徑是一個直譯器會先進行搜尋的所有目錄的列表。如想要匯入模組 support,需要把命令放在指令碼的頂端:

support.py 檔案程式碼

#!/usr/bin/python3 
# Filename: support.py
def print_func( par ): 
    print ("Hello : ", par)
    return

test.py 引入 support 模組:

#!/usr/bin/python3 
# Filename: test.py 
# 匯入模組
import support 

# 現在可以呼叫模組裡包含的函數了 
support.print_func("Runoob")

以上例項輸出結果:

$ python3 test.py 
Hello :  Runoob

一個模組只會被匯入一次,不管你執行了多少次import。這樣可以防止匯入模組被一遍又一遍地執行。

當我們使用import語句的時候,Python直譯器是怎樣找到對應的檔案的呢?

這就涉及到Python的搜尋路徑,搜尋路徑是由一系列目錄名組成的,Python直譯器就依次從這些目錄中去尋找所引入的模組。

這看起來很像環境變數,事實上,也可以通過定義環境變數的方式來確定搜尋路徑。

搜尋路徑是在Python編譯或安裝的時候確定的,安裝新的庫應該也會修改。搜尋路徑被儲存在sys模組中的path變數,做一個簡單的實驗,在互動式直譯器中,輸入以下程式碼:

>>> import sys
>>> sys.path
['', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']
>>> 

sys.path 輸出是一個列表,其中第一項是空串'',代表當前目錄(若是從一個指令碼中打印出來的話,可以更清楚地看出是哪個目錄),亦即我們執行python直譯器的目錄(對於指令碼的話就是執行的指令碼所在的目錄)。

因此若像我一樣在當前目錄下存在與要引入模組同名的檔案,就會把要引入的模組遮蔽掉。

瞭解了搜尋路徑的概念,就可以在指令碼中修改sys.path來引入一些不在搜尋路徑中的模組。

現在,在直譯器的當前目錄或者 sys.path 中的一個目錄裡面來建立一個fibo.py的檔案,程式碼如下:

例項

# 斐波那契(fibonacci)數列模組
def fib(n): 
# 定義到 n 的斐波那契數列 
    a, b = 0, 1 
    while b < n:
        print(b, end=' ')
        a, b = b, a+b 
    print() 
def fib2(n): 
# 返回到 n 的斐波那契數列 
    result = [] 
    a, b = 0, 1 
    while b < n: 
        result.append(b)
        a, b = b, a+b 
    return result

然後進入Python直譯器,使用下面的命令匯入這個模組:

import fibo

這樣做並沒有把直接定義在fibo中的函式名稱寫入到當前符號表裡,只是把模組fibo的名字寫到了那裡。

可以使用模組名稱來訪問函式:

例項

>>>fibo.fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 
>>> fibo.fib2(100) 
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] 
>>> fibo.__name__ 
'fibo'

如果你打算經常使用一個函式,你可以把它賦給一個本地的名稱:

>>> fib = fibo.fib
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

from … import 語句

Python 的 from 語句讓你從模組中匯入一個指定的部分到當前名稱空間中,語法如下:

from modname import name1[, name2[, ... nameN]]

例如,要匯入模組 fibo 的 fib 函式,使用如下語句:

>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

這個宣告不會把整個fibo模組匯入到當前的名稱空間中,它只會將fibo裡的fib函式引入進來。

from … import * 語句

把一個模組的所有內容全都匯入到當前的名稱空間也是可行的,只需使用如下宣告:

from modname import *

這提供了一個簡單的方法來匯入一個模組中的所有專案。然而這種宣告不該被過多地使用。

深入模組

模組除了方法定義,還可以包括可執行的程式碼。這些程式碼一般用來初始化這個模組。這些程式碼只有在第一次被匯入時才會被執行。

每個模組有各自獨立的符號表,在模組內部為所有的函式當作全域性符號表來使用。

所以,模組的作者可以放心大膽的在模組內部使用這些全域性變數,而不用擔心把其他使用者的全域性變數搞花。

從另一個方面,當你確實知道你在做什麼的話,你也可以通過 modname.itemname 這樣的表示法來訪問模組內的函式。

模組是可以匯入其他模組的。在一個模組(或者指令碼,或者其他地方)的最前面使用 import 來匯入一個模組,當然這只是一個慣例,而不是強制的。被匯入的模組的名稱將被放入當前操作的模組的符號表中。

還有一種匯入的方法,可以使用 import 直接把模組內(函式,變數的)名稱匯入到當前操作模組。比如:

>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

這種匯入的方法不會把被匯入的模組的名稱放在當前的字元表中(所以在這個例子裡面,fibo 這個名稱是沒有定義的)。

這還有一種方法,可以一次性的把模組中的所有(函式,變數)名稱都匯入到當前模組的字元表:

這將把所有的名字都匯入進來,但是那些由單一下劃線(_)開頭的名字不在此例。大多數情況, Python程式設計師不使用這種方法,因為引入的其它來源的命名,很可能覆蓋了已有的定義。

__name__屬性

一個模組被另一個程式第一次引入時,其主程式將執行。如果我們想在模組被引入時,模組中的某一程式塊不執行,我們可以用__name__屬性來使該程式塊僅在該模組自身執行時執行。

#!/usr/bin/python3
# Filename: using_name.py

if __name__ == '__main__':
   print('程式自身在執行')
else:
   print('我來自另一模組')
執行輸出如下:

$ python using_name.py
程式自身在執行
$ python
>>> import using_name
我來自另一模組
>>>

說明: 每個模組都有一個__name__屬性,當其值是'__main__'時,表明該模組自身在執行,否則是被引入。

說明:__name__ 與 __main__ 底下是雙下劃線, _ _ 是這樣去掉中間的那個空格。

dir() 函式

內建的函式 dir() 可以找到模組內定義的所有名稱。以一個字串列表的形式返回

如果沒有給定引數,那麼 dir() 函式會羅列出當前定義的所有名稱:

>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir() # 得到一個當前模組中定義的屬性列表
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
>>> a = 5 # 建立一個新的變數 'a'
>>> dir()
['__builtins__', '__doc__', '__name__', 'a', 'sys']
>>>
>>> del a # 刪除變數名a
>>>
>>> dir()
['__builtins__', '__doc__', '__name__', 'sys']
>>>

標準模組

Python 本身帶著一些標準的模組庫,在 Python 庫參考文件中將會介紹到(就是後面的"庫參考文件")。

有些模組直接被構建在解析器裡,這些雖然不是一些語言內建的功能,但是他卻能很高效的使用,甚至是系統級呼叫也沒問題。

這些元件會根據不同的作業系統進行不同形式的配置,比如 winreg 這個模組就只會提供給 Windows 系統。

包是一種管理 Python 模組名稱空間的形式,採用"點模組名稱"。

比如一個模組的名稱是 A.B, 那麼他表示一個包 A中的子模組 B 。

就好像使用模組的時候,你不用擔心不同模組之間的全域性變數相互影響一樣,採用點模組名稱這種形式也不用擔心不同庫之間的模組重名的情況。

這樣不同的作者都可以提供 NumPy 模組,或者是 Python 圖形庫。

不妨假設你想設計一套統一處理聲音檔案和資料的模組(或者稱之為一個"包")。

現存很多種不同的音訊檔案格式(基本上都是通過後綴名區分的,例如: .wav,:file:.aiff,:file:.au,),所以你需要有一組不斷增加的模組,用來在不同的格式之間轉換。

並且針對這些音訊資料,還有很多不同的操作(比如混音,添加回聲,增加均衡器功能,建立人造立體聲效果),所以你還需要一組怎麼也寫不完的模組來處理這些操作。

這裡給出了一種可能的包結構(在分層的檔案系統中):

sound/                          頂層包
      __init__.py               初始化 sound 包
      formats/                  檔案格式轉換子包
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  聲音效果子包
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  filters 子包
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

在匯入一個包的時候,Python 會根據 sys.path 中的目錄來尋找這個包中包含的子目錄。

目錄只有包含一個叫做 __init__.py 的檔案才會被認作是一個包,主要是為了避免一些濫俗的名字(比如叫做 string)不小心的影響搜尋路徑中的有效模組。

最簡單的情況,放一個空的 :file:__init__.py就可以了。當然這個檔案中也可以包含一些初始化程式碼或者為(將在後面介紹的) __all__變數賦值。

使用者可以每次只匯入一個包裡面的特定模組,比如:

import sound.effects.echo

這將會匯入子模組:sound.effects.echo。 他必須使用全名去訪問:

sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

還有一種匯入子模組的方法是:

from sound.effects import echo

這同樣會匯入子模組: echo,並且他不需要那些冗長的字首,所以他可以這樣使用:

echo.echofilter(input, output, delay=0.7, atten=4)

還有一種變化就是直接匯入一個函式或者變數:

from sound.effects.echo import echofilter

同樣的,這種方法會匯入子模組: echo,並且可以直接使用他的 echofilter() 函式:

echofilter(input, output, delay=0.7, atten=4)

注意當使用from package import item這種形式的時候,對應的item既可以是包裡面的子模組(子包),或者包裡面定義的其他名稱,比如函式,類或者變數。

import語法會首先把item當作一個包定義的名稱,如果沒找到,再試圖按照一個模組去匯入。如果還沒找到,恭喜,一個:exc:ImportError 異常被丟擲了。

反之,如果使用形如import item.subitem.subsubitem這種匯入形式,除了最後一項,都必須是包,而最後一項則可以是模組或者是包,但是不可以是類,函式或者變數的名字。