Python風格總結:模塊調用

在前面的幾個章節中我們腳本上是用 python 解釋器來編程,如果你從 Python 解釋器退出再進入,那麼你定義的所有的方法和變量就都消失了。

爲此 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')

結果輸出:

命令行參數如下:
D:/PycharmProjects/TestPython/TestMain.py


Python 路徑爲: ['D:\\PycharmProjects\\TestPython', 'D:\\PycharmProjects\\TestPython', 'C:\\Python\\Python37\\python37.zip', 'C:\\Python\\Python37\\DLLs', 'C:\\Python\\Python37\\lib', 'C:\\Python\\Python37', 'D:\\PycharmProjects\\TestPython\\venv', 'D:\\PycharmProjects\\TestPython\\venv\\lib\\site-packages', 'D:\\PycharmProjects\\TestPython\\venv\\lib\\site-packages\\setuptools-40.8.0-py3.7.egg', 'D:\\PycharmProjects\\TestPython\\venv\\lib\\site-packages\\pip-19.0.3-py3.7.egg'] 

  • 1、import sys 引入 python 標準庫中的 sys.py 模塊;這是引入某一模塊的方法。
  • 2、sys.argv 是一個包含命令行參數的列表。
  • 3、sys.path 包含了一個 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)

test.py 引入 support 模塊:

test.py 文件代碼

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

# 導入模塊
import support

# 現在可以調用模塊裏包含的函數了
support.print_func("Runoob")

結果輸出:

Hello :  Runoob

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

當我們使用import語句的時候,Python解釋器是怎樣找到對應的文件的呢?

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

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

from … import 語句

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

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

例如,fibo文件代碼:

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

常規導入fibo模塊,調用fib和fib2函數:

import fibo
fibo.fib(1000)
print(fibo.fib2(100))

fib = fibo.fib #如果你打算經常使用一個函數,你可以把它賦給一個本地的名稱
fib(500)

 結果輸出:

D:\PycharmProjects\TestPython\venv\Scripts\python.exe D:/PycharmProjects/TestPython/TestMain.py
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
1 1 2 3 5 8 13 21 34 55 89 144 233 377 

單獨導入fibo模塊的fib函數如下:

from fibo import fib, fib2
fib(500)

結果輸出:

D:\PycharmProjects\TestPython\venv\Scripts\python.exe D:/PycharmProjects/TestPython/TestMain.py
1 1 2 3 5 8 13 21 34 55 89 144 233 377 

__name__屬性

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

例如using_name.py模塊

#!/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() 可以找到模塊內定義的所有名稱。以一個字符串列表的形式返回:

>>> 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() 函數會羅列出當前定義的所有名稱:(變量、函數等等)

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

 

 

 

 

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