1. 程式人生 > >Python3 模塊

Python3 模塊

python3 模塊

Edit


筆記內容:Python3 模塊
筆記日期:2017-11-02


Python3 模塊

  • Python3 模塊簡介

  • import 語句

  • from…import 語句

  • from…import* 語句

  • name屬性

  • dir() 函數

  • 標準模塊

  • 從一個包中導入*


Python3 模塊簡介

模塊是一個包含所有你定義的函數和變量的文件,其後綴名是.py。模塊可以被別的程序引入,以使用該模塊中的函數等功能。這也是使用 python 標準庫的方法,我們可以把寫好的一些可復用的函數,封裝成模塊然後發布到Python的本地庫中。然後在其他的程序就可以導入你這個寫好的模塊了。簡單來說模塊就像一個常用的零件,例如組裝一個高達模型時,可以把現成的零件拿過來使用,加快我們的組裝速度,如果零件都需要我們自己制作就會慢很多而且難度也大。而標準庫中的模塊就是Python自帶的零件,提供我們去使用,我們也可以開發自己的模塊,自己開發的模塊發布到本地後,一樣可以像標準庫中的模塊去使用它們。

下面是一個使用 python 標準庫中模塊的例子。

import sys  # 導入模塊的關鍵字是import,這裏導入了sys模塊

print("命令行參數如下:")
for i in sys.argv:  # 通過模塊可以調用它裏面的變量或者函數
    print(i)

print("\n\nPython路徑為:")
for path in sys.path:
    print(path)

運行結果:

命令行參數如下:
E:/PythonProject/TestMould.py

Python路徑為:
E:\PythonProject
E:\PythonProject
E:\Python3.6\python36.zip

E:\Python3.6\DLLs
E:\Python3.6\lib
E:\Python3.6
E:\Python3.6\lib\site-packages

1、import sys 引入 python 標準庫中的 sys.py 模塊;這是引入某一模塊的方法。
2、sys.argv 是一個包含命令行參數的列表。
3、sys.path 包含了一個 Python 解釋器自動查找所需模塊的路徑的列表。


import 語句

import 語句用來導入Python庫中的模塊,模塊需要導入之後才能使用,語法如下:

import module1[, module2[,… moduleN]

當解釋器遇到 import 語句,如果模塊在當前的搜索路徑就會被導入。搜索路徑是一個解釋器會事先進行搜索的所有目錄的列表。

例如:我們在PyCharm工具中創建一個model.py文件,這個文件就相當於是一個模塊了,接著可以在文件裏自定義一個函數:

技術分享

然後再創建一個Hello.py文件,在這個文件中可以通過import導入這個模塊,通過這個導入的模塊就可以調用此模塊裏面的函數:

# Filename: Hello.py

# 導入模塊
import model

# 現在可以調用模塊裏包含的函數了
model.println()

運行結果:

Test!

如果你打算經常使用一個函數,你可以把它賦值給一個變量:

import model

println=model.println
println()

運行結果:

Test!

以上示例屬於是一個自定義模塊的創建和導入過程。

一個模塊只會被導入一次,不管你執行了多少次import語句,所以這樣可以防止導入模塊被一遍又一遍地執行。
當我們使用import語句的時候,Python解釋器是怎樣找到對應的文件的呢?
這就涉及到了Python的搜索路徑:

  • 搜索路徑是由一系列目錄名組成的

  • Python解釋器就依次從這些目錄中去尋找所引入的模塊。

  • 搜索路徑是在Python編譯或安裝的時候確定的,安裝新的庫應該也會修改。

  • 搜索路徑被存儲在sys模塊中的path變量

這看起來很像環境變量,事實上,也可以通過定義環境變量的方式來確定搜索路徑。
可以做一個簡單的實驗來查看Python的搜索路徑,代碼示例:

import sys

print(sys.path) # 將目錄列表打印出來

運行結果:

[‘E:\PythonProject’, ‘E:\PythonProject’, ‘E:\Python3.6\python36.zip’, ‘E:\Python3.6\DLLs’, ‘E:\Python3.6\lib’, ‘E:\Python3.6’, ‘E:\Python3.6\lib\site-packages’]

sys.path 返回的是一個列表,其中第一項,代表當前目錄(如果從解釋器中執行的話,會是一個空字符串),也就是這個.py文件的所在路徑。


from…import 語句

Python的from語句可以讓你從模塊中導入指定的函數或變量到當前的腳本中,語法如下:

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

例如,要導入 model模塊的 println函數,代碼示例:

from model import println

println()

這個聲明不會把整個model模塊導入到當前的腳本中,它只會將model裏的println函數引入進來,然後我們就可以直接對這個函數進行調用了。
如果要導入多個函數或者變量的話,需要使用逗號隔開。


from…import* 語句

把一個模塊的所有內容全都導入到當前的腳本中是可行的,只需使用如下聲明:

from modname import *

這提供了一個簡單的方法來導入一個模塊中的所有項目。然而這種聲明不該被過多地使用。


name屬性

每一個模塊或者說腳本文件都會有一個主程序或者說代碼的執行起點,類似於Java、C/C++、C#中的main方法,當腳本運行時,這個主程序就會被執行。這個主程序在執行時會被分配一個名字,但是這個名字並非是固定的,例如:在作為一個腳本被執行時,這個主程序的名字為_main_,在另一個腳本被做為一個導入的模塊執行時,這個主程序的名字就為模塊的名稱。而相對的每一個腳本都有一個自己的_name_屬性,這個屬性的值對應著當前主程序的名稱,下面用實際例子演示一下:

#filename:TestMould.py

if __name__ == ‘__main__‘:  # 作為一個腳本執行時主程序的名稱為__main__
    print(__name__)
    print("我被作為當前腳本運行")
else:
    print(__name__)
    print("我被作為另一個腳本中的一個模塊運行")

運行結果:

_main_
程序自身在運行

如果在另一個腳本中被當做一個模塊執行時,_name_ 屬性的值就不會為_main_

#filename:Hello.py

import TestMould  # 被作為另一個腳本的導入模塊執行時,主程序的名稱為模塊的名稱

運行結果:

TestMould
我被作為另一個腳本中的一個模塊運行

說明: 每個模塊(腳本)都有一個_name_屬性,當其值是_main_時,表明該模塊自身在運行也就是作為腳本在運行,否則就是被作為引入模塊在運行。而不管是作為腳本執行還是作為引入模塊執行,主程序都會被執行,只不過名稱不一樣罷了。


dir() 函數

dir()是一個內置的函數(BIF),這個函數可以找到導入的模塊內定義的所有函數和屬性、變量的名稱。然後以一個字符串列表的形式返回:

>>> import sys
>>> dir(sys)
[‘__displayhook__‘, ‘__doc__‘, ‘__excepthook__‘, ‘__name__‘, ‘__package__‘, ‘__stderr__‘, ‘__stdin
__‘, ‘__stdout__‘, ‘_clear_type_cache‘, ‘_current_frames‘, ‘_getframe‘, ‘_mercurial‘, ‘api_version
‘, ‘argv‘, ‘builtin_module_names‘, ‘byteorder‘, ‘call_tracing‘, ‘callstats‘, ‘copyright‘, ‘displa
yhook‘, ‘dllhandle‘, ‘dont_write_bytecode‘, ‘exc_clear‘, ‘exc_info‘, ‘exc_type‘, ‘excepthook‘, ‘e
xec_prefix‘, ‘executable‘, ‘exit‘, ‘flags‘, ‘float_info‘, ‘float_repr_style‘, ‘getcheckinterval‘,
 ‘getdefaultencoding‘, ‘getfilesystemencoding‘, ‘getprofile‘, ‘getrecursionlimit‘, ‘getrefcount‘, 
 ‘getsizeof‘, ‘gettrace‘, ‘getwindowsversion‘, ‘hexversion‘, ‘long_info‘, ‘maxint‘, ‘maxsize‘, ‘
 maxunicode‘, ‘meta_path‘, ‘modules‘, ‘path‘, ‘path_hooks‘, ‘path_importer_cache‘, ‘platform‘, ‘
 prefix‘, ‘ps1‘, ‘ps2‘, ‘py3kwarning‘, ‘setcheckinterval‘, ‘setprofile‘, ‘setrecursionlimit‘, ‘s
 ettrace‘, ‘stderr‘, ‘stdin‘, ‘stdout‘, ‘subversion‘, ‘version‘, ‘version_info‘, ‘warnoptions‘,
  ‘winver‘]
>>>

如果dir函數中不傳遞參數,那麽 dir() 函數會羅列出當前腳本中定義的所有函數、模塊、變量、屬性的名稱:

>>> import sys
>>> def test():
...     print("test")
... 
>>> a=123
>>> dir()
[‘__builtins__‘, ‘__doc__‘, ‘__name__‘, ‘__package__‘, ‘a‘, ‘sys‘, ‘test‘]
>>>


標準模塊

Python 本身帶著一些標準的模塊庫,之前也提到過,具體的標準模塊會在一篇單獨的文章中介紹一些常用的(因為太多了)。
有些模塊直接被構建在解析器裏,這些雖然不是一些語言內置的功能,但是他卻能很高效的使用,甚至是系統級調用也沒問題。
這些組件會根據不同的操作系統進行不同形式的配置,比如 winreg 這個模塊就只會提供給 Windows 系統。
應該註意到這有一個特別的模塊 sys,sys是System(系統)的縮寫 ,它內置在每一個 Python 解析器中。變量 sys.ps1 和 sys.ps2 定義了主提示符和副提示符所對應的字符串:

>>> import sys
>>> sys.ps1  # 解釋器中的主提示符
‘>>> ‘
>>> sys.ps2  # 解釋器中的副提示符(當我們寫一個函數時就會顯示這個副提示符)
‘... ‘
>>> sys.ps1 = ‘C> ‘  # 把解釋器中的主提示符更改為‘C> ‘
C> print(‘Yuck!‘)
Yuck!
C>


包是一種管理 Python 模塊命名空間的形式,類似於一個文件夾,而這個文件夾下會有很多子文件,這些子文件就是一個個的模塊。當我們需要使用一個包下的某個模塊時,和其他編程語言一樣需要使用 . 來作為訪問符。
比如一個模塊的名稱是 A.B, 那麽他表示一個包 A中的子模塊 B 。
就好像使用模塊的時候,你不用擔心不同模塊之間的全局變量相互影響一樣,采用點模塊名稱這種形式也不用擔心不同庫之間的模塊重名的情況。
這樣不同的作者都可以提供 NumPy 模塊,或者是 Python 圖形庫。
不妨假設你想設計一套統一處理聲音文件和數據的模塊(或者稱之為一個”包”)。
現存很多種不同的音頻文件格式(基本上都是通過後綴名區分的,例如: .wav,:file:.aiff,:file:.au,),所以你需要有一組不斷增加的模塊,用來在不同的格式之間轉換。
並且針對這些音頻數據,還有很多不同的操作(比如混音,添加回聲,增加均衡器功能,創建人造立體聲效果),所你還需要一組怎麽也寫不完的模塊來處理這些操作。
這裏給出了一種可能的包結構(在分層的文件系統中):

1.sound/                          頂層包
2.      __init__.py               初始化 sound 包
3.      formats/                  文件格式轉換子包
4.              __init__.py
5.              wavread.py
6.              wavwrite.py
7.              aiffread.py
8.              aiffwrite.py
9.              auread.py
10.              auwrite.py
11.              ...
12.      effects/                  聲音效果子包
13.              __init__.py
14.              echo.py
15.              surround.py
16.              reverse.py
17.              ...
18.      filters/                  filters 子包
19.              __init__.py
20.              equalizer.py
21.              vocoder.py
22.              karaoke.py
23.              ...

在導入一個包的時候,Python 會根據 sys.path 中的目錄來尋找這個包中包含的子目錄。
目錄只有包含一個叫做 init.py 的文件才會被認作是一個包,主要是為了避免一些濫俗的名字(比如叫做 string)不小心的影響搜索路徑中的有效模塊。
最簡單的情況,放一個空的_init_.py文件就可以了。當然這個文件中也可以包含一些初始化代碼或者為(將在後面介紹的) _all_變量賦值。
用戶可以每次只導入一個包裏面的特定模塊,示例:

import sound.effects.echo    # 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當作一個包定義的名稱,如果沒找到,再試圖按照一個模塊去導入。如果還沒找到,恭喜一個:ImportError 異常被拋出了。
反之,如果使用形如import item.subitem.subsubitem這種導入形式,除了最後一項,都必須是包,而最後一項則可以是模塊或者是包,但是不可以是類,函數或者變量的名字。


從一個包中導入:*

設想一下,如果我們使用 from sound.effects import * 會發生什麽?
Python 會進入文件系統,找到這個包裏面所有的子模塊,一個一個的把它們都導入進來。
但是很不幸,這個方法在 Windows平臺上工作的就不是非常好,因為Windows是一個大小寫不區分的系統。
在這類平臺上,沒有人敢擔保一個叫做 ECHO.py 的文件導入為模塊 echo 還是 Echo 甚至 ECHO。
(例如,Windows 95就很討厭的把每一個文件的首字母大寫顯示)而且 DOS 的 8+3 命名規則對長模塊名稱的處理會把問題搞得更糾結。
為了解決這個問題,只能煩勞包作者提供一個精確的包的索引了。
導入語句遵循如下規則:如果包定義文件 _init_.py 存在一個叫做 _all_ 的列表變量,那麽在使用 from package import * 的時候就把這個列表中的所有名字作為包內容導入。
作為包的作者,可別忘了在更新包之後保證 _all_ 也更新了啊。你說我就不這麽做,我就不使用導入*這種用法,好吧,沒問題,誰讓你是老板呢。這裏有一個例子,在 sounds/effects/_init_.py中包含如下代碼:

__all__ = ["echo", "surround", "reverse"]

這表示當你使用from sound.effects import *這種用法時,你只會導入包裏面這三個子模塊。
如果 _all_ 真的沒有定義,那麽使用from sound.effects import *這種語法的時候,就不會導入包 sound.effects 裏的任何子模塊。他只是把包sound.effects和它裏面定義的所有內容導入進來(可能運行_init_.py裏定義的初始化代碼)。
這會把 _init_.py 裏面定義的所有名字導入進來。並且他不會破壞掉我們在這句話之前導入的所有明確指定的模塊。看下這部分代碼:

import sound.effects.echo
import sound.effects.surround
from sound.effects import *

這個例子中,在執行from…import前,包sound.effects中的echo和surround模塊都被導入到當前的命名空間中了。(當然如果定義了_all_就更沒問題了)
通常我們並不主張使用*這種方法來導入模塊,因為這種方法經常會導致代碼的可讀性降低。不過這樣倒的確是可以省去不少敲鍵的功夫,而且一些模塊都設計成了只能通過特定的方法導入。
記住,使用from Package import specific_submodule這種方法永遠不會有錯。事實上,這也是推薦的方法。除非是你要導入的子模塊有可能和其他包的子模塊重名。
如果在結構中包是一個子包(比如這個例子中對於包sound來說),而你又想導入兄弟包(同級別的包)你就得使用導入絕對的路徑來導入。比如,如果模塊sound.filters.vocoder 要使用包sound.effects中的模塊echo,你就要寫成 from sound.effects import echo。

from . import echo
from .. import formats
from ..filters import equalizer

無論是隱式的還是顯式的相對導入都是從當前模塊開始的。主模塊的名字永遠是_main_,一個Python應用程序的主模塊,應當總是使用絕對路徑引用。
包還提供一個額外的屬性_path_。這是一個目錄列表,裏面每一個包含的目錄都有為這個包服務的_init_.py,你得在其他_init_.py被執行前定義哦。可以修改這個變量,用來影響包含在包裏面的模塊和子包。
這個功能並不常用,一般用來擴展包裏面的模塊。



本文出自 “zero” 博客,請務必保留此出處http://zero01.blog.51cto.com/12831981/1978895

Python3 模塊