python學習七:模塊

模塊

模塊

模塊是一個包含全部你定義的函數和變量的文件,其後綴名是.py。模塊能夠被別的程序引入,以使用該模塊中的函數等功能。這也是使用 python 標準庫的方法。 舉例:python

#!/usr/bin/python3
# 文件名: using_sys.py
 
import sys
 
print('命令行參數以下:')
for i in sys.argv:
   print(i)
 
print('\n\nPython 路徑爲:', sys.path, '\n')
複製代碼

執行結果以下:linux

$ python using_sys.py 參數1 參數2
命令行參數以下:
using_sys.py
參數1
參數2


Python 路徑爲: ['/root', '/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'] 
複製代碼
  1. import sys 引入 python 標準庫中的 sys.py 模塊;這是引入某一模塊的方法。
  2. sys.argv 是一個包含命令行參數的列表。
  3. sys.path 包含了一個 Python 解釋器自動查找所需模塊的路徑的列表。

import語句

想使用 Python 源文件,只需在另外一個源文件裏執行 import 語句,語法以下:api

import module1[, module2[,... moduleN]
複製代碼

當解釋器遇到 import 語句,若是模塊在當前的搜索路徑就會被導入。 搜索路徑是一個解釋器會先進行搜索的全部目錄的列表。如想要導入模塊 support,須要把命令放在腳本的頂端。 一個模塊只會被導入一次,無論你執行了多少次import。這樣能夠防止導入模塊被一遍又一遍地執行。bash

當咱們使用import語句的時候,Python解釋器是怎樣找到對應的文件的呢? 這就涉及到Python的搜索路徑,搜索路徑是由一系列目錄名組成的,Python解釋器就依次從這些目錄中去尋找所引入的模塊。 這看起來很像環境變量,事實上,也能夠經過定義環境變量的方式來肯定搜索路徑。 搜索路徑是在Python編譯或安裝的時候肯定的,安裝新的庫應該也會修改。搜索路徑被存儲在sys模塊中的path變量,作一個簡單的實驗,在交互式解釋器中,輸入如下代碼:app

>>> 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解釋器,使用下面的命令導入這個模塊:ui

>>> import fibo
複製代碼

這樣作並無把直接定義在fibo中的函數名稱寫入到當前符號表裏,只是把模塊fibo的名字寫到了那裏。 可使用模塊名稱來訪問函數:spa

>>>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 語句讓你從模塊中導入一個指定的部分到當前命名空間中,語法以下:debug

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 *
複製代碼

這將把全部的名字都導入進來,可是那些由單一下劃線(_)開頭的名字不在此例。大多數狀況,不推薦使用這種方法,由於引入的其它來源的命名,極可能覆蓋了已有的定義。

__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__'時,代表該模塊自身在運行,不然是被引入。

dir() 函數

內置的函數 dir() 能夠找到模塊內定義的全部名稱。以一個字符串列表的形式返回:

>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)  
['__displayhook__', '__doc__', '__excepthook__', '__loader__', '__name__',
 '__package__', '__stderr__', '__stdin__', '__stdout__',
 '_clear_type_cache', '_current_frames', '_debugmallocstats', '_getframe',
 '_home', '_mercurial', '_xoptions', 'abiflags', 'api_version', 'argv',
 'base_exec_prefix', 'base_prefix', 'builtin_module_names', 'byteorder',
 'call_tracing', 'callstats', 'copyright', 'displayhook',
 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix',
 'executable', 'exit', 'flags', 'float_info', 'float_repr_style',
 'getcheckinterval', 'getdefaultencoding', 'getdlopenflags',
 'getfilesystemencoding', 'getobjects', 'getprofile', 'getrecursionlimit',
 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettotalrefcount',
 'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
 'intern', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path',
 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1',
 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit',
 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout',
 'thread_info', 'version', 'version_info', 'warnoptions']
複製代碼

若是沒有給定參數,那麼 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 模塊命名空間的形式,採用"點模塊名稱"。 好比一個模塊的名稱是 A.B, 那麼他表示一個包 A中的子模塊 B。 就好像使用模塊的時候,你不用擔憂不一樣模塊之間的全局變量相互影響同樣,採用點模塊名稱這種形式也不用擔憂不一樣庫之間的模塊重名的狀況。 這樣不一樣的做者均可以提供 NumPy 模塊,或者是 Python 圖形庫。 這裏給出了一種可能的包結構(在分層的文件系統中):

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這種導入形式,除了最後一項,都必須是包,而最後一項則能夠是模塊或者是包,可是不能夠是類,函數或者變量的名字。

從一個包中導入*

設想一下,若是咱們使用 from sound.effects import *會發生什麼? Python 會進入文件系統,找到這個包裏面全部的子模塊,一個一個的把它們都導入進來。 可是很不幸,這個方法在 Windows平臺上工做的就不是很是好,由於Windows是一個大小寫不區分的系統。 在這類平臺上,沒有人敢擔保一個叫作 ECHO.py 的文件導入爲模塊 echo 仍是 Echo 甚至 ECHO。 (例如,Windows 95就很討厭的把每個文件的首字母大寫顯示)並且 DOS 的 8+3 命名規則對長模塊名稱的處理會把問題搞得更糾結。 爲了解決這個問題,只能煩勞包做者提供一個精確的包的索引了。 導入語句遵循以下規則:若是包定義文件 __init__.py 存在一個叫作 __all__ 的列表變量,那麼在使用 from package import * 的時候就把這個列表中的全部名字做爲包內容導入。 做爲包的做者,可別忘了在更新包以後保證 __all__ 也更新了啊。你說我就不這麼作,我就不使用導入*這種用法,好吧,沒問題,誰讓你是老闆呢。這裏有一個例子,在file: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被執行前定義哦。能夠修改這個變量,用來影響包含在包裏面的模塊和子包。 這個功能並不經常使用,通常用來擴展包裏面的模塊。

相關文章
相關標籤/搜索