almost 4 years ago

  • 章節簡介
  • 模組與套件
    • 模組與匯入
    • 名稱空間(namespace)
    • 匯入到頂層空間
    • 不安全的匯入
    • 套件
  • 第三方程式庫
    • PyPI
    • Python的套件管理程式-pip
    • 常用套件簡介
    • 上傳自己的套件
  • 虛擬環境
    • 使用virtualenv
    • 使用virtualenvwrapper
    • 使用虛擬環境來解決問題
  • 本章小結

章節簡介

在這個章節我們會學到:

  • 什麼是模組?什麼是套件?
  • 名稱空間的使用與匯入的手法
  • 如何使用與管理第三方程式庫
  • 使用虛擬環境讓任務能妥善進行

在了解了基本的Python程式設計之後,我們有必要再花一個章節來探討Python中的模組與套件。透過使用現成的模組與套件,我們可以減少大量重複而不必要的開發,同時也能夠使我們的設計更有架構跟章法,本章將會由模組和套件的概念說起,包含匯入、名稱空間的使用等議題,接著會說明如何取得和安裝第三方套件,最後還會介紹如何使用虛擬環境來讓我們的工作更順利。

模組與套件

模組與匯入

一個模組簡單來說就是一個Python檔案,而在模組中(一個Python檔案)會出現的不外乎就是運算、函式與類別了。而我們主要還是想要利用函式跟類別這兩部分。我們簡單看一個匯入模組的例子:

test.py
import sys

print sys.argv

接著我們來執行這個程式:

$ python test.py hello world
['test.py', 'hello', 'world']

沒錯!就是那麼簡單!使用import關鍵字來匯入sys模組(此模組是Python內建的模組,他也是一個Python檔案),並且透過模組名稱與.來取用該模組中的一個資料sys.argv,這其實是一個標準的清單,裡面的第零個元素就是我們的Python檔名,第一個元素是緊跟在test.py後面的第一個命令列參數,第二個元素是第二個命令列參數,以此類推。

sys.argv是個很常用的清單,他能夠幫助我們取得命令列上的參數。

我們也可以幫模組取個別名:

test.py
import sys as s

print s.argv

在這裡我們透過as為sys模組取了一個別名s,往後我們要使用到該模組的東西時,可以改用s來存取。

還有一點值得一提的是,我們可以用一個import敘述匯入多個模組:

import os, sys

名稱空間(namespace)

談到模組就不得不提到名稱空間了,名稱空間顧名思義就是收集名稱的空間,每個名稱空間只會認得自己空間內的名字。這是什麼意思呢?讓我們打開Python shell做點試驗吧:

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>> import sys
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'sys']

dir是一個內建函式,他能夠列出指定名稱空間中所有的名稱,當我們不提供參數的時候,dir會列出shell中最上層名稱空間中的名字。我們發現,當我們匯入sys後,頂層名稱空間中多了'sys'這個name。

>>> dir(sys)
[..., '_mercurial', 'api_version', 'argv', ...]
>>> dir(argv)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'argv' is not defined

如果我們再往sys裡面看,我們可以找到argv這個名字。但是為什麼dir(argv)會出現錯誤呢?這是由於頂層空間中並沒有argv這個名字,所以一旦要使用我們便不認識他了,那該怎麼辦呢?沒關係,起碼shell認識sys這個名字,而sys又認識argv,我們透過.就可以跨過一層又一層,存取到我們要的東西:

>>> dir(sys.argv)

這跟模組有什麼關係呢?原來是當我們匯入模組時,Python會用模組的名稱建立一個名稱空間,該空間收集了模組中函式、類別的名字,我們透過.做階層式的存取,便能取用這些函式和類別為己用了。

匯入到頂層空間

我們在這裡還要介紹一個匯入的手法:

>>> from sys import argv
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'argv', 'sys']

from sys import argv的手法會避免建立以sys為名的名稱空間,而直接將argv加入頂層空間,這樣做的好處是,當我們要存取argv的時候,不必再透過sys,我們可以直接取用argv。

我們也可以透過*來一次匯入所有名字到頂層空間:

>>> from sys import *

但要注意一點:import越多東西,Python負擔越大,所以我們應該盡量只import會使用到的範圍。

不安全的匯入

不安全的匯入會造成名稱衝突,我們應當設法避免,讓我們先舉個例子,我們設想有兩個模組M1和M2,他們擁有一個同名的函式叫作func,當我們這樣匯入:

from M1 import *
from M2 import *

我們會發現名稱衝突的問題,究竟我們呼叫func的時候是呼叫哪個模組的呢?答案是會呼叫後匯入模組的func。雖然Python仍能運行,但是這個重複的名稱會讓我們在之後的使用上造成誤會進而產生錯誤。

在此我們也能夠看出名稱空間設計的目的,它能透過階層性的存取(加入了一些足以辨別不同的前綴名稱)來避免名稱衝突,以下列出一些不太安全的匯入方式:

import os.path as path
from os import path
from os.path import *

上述的匯入方式均會使得os這個前綴消失使得名稱衝突的可能性大增。 讀者們可能會發現,使用from import語法幾乎都會遭遇危險性上升的問題,沒錯!這是一個較不推薦的匯入手法,可是在一些較複雜的模組或套件中,我們依然會適度地採用這種匯入以避免過長的階層存取,例如在Django中。

套件

模組就是一個檔案,而套件就是一個目錄!一個擁有著__init__.py檔案的目錄就會被Python視為一個套件,一個套件裡面收集了若干相關的模組或是套件,簡單來說套件就是個模組庫、函式庫。

假設我們自己寫了個套件叫做my_package:

my_package/
├── __init__.py
├── m1.py
├── m2.py
└── sub_package
    ├── __init__.py
    ├── m3.py
    └── m4.py

這個目錄底下要有一個__init__.py的檔案以確保Python認定它為套件,還有幾個模組跟一個子套件,子套件底下也有一個__init__.py和若干模組。

接著我們來試著匯入,我們在my_package底下加入一個檔案main.py

main.py
import m1
import sub_package
import sub_package.m3

當我們要實際匯入一個模組的時候,我們會省略.py這個副檔名,接著我們可以匯入子套件sub_package或是裡面的模組m3,我們發現匯入套件的方式跟匯入模組是一模一樣的。

接著我們執行main.py,我們會發現在my_package底下會出現一個新的檔案m1.pyc,在sub_package底下也會出現m3.pyc,這些pyc檔是Python的位元組碼檔案。當Python第一次匯入模組時,會對該模組進行位元組編譯,產生出一個byte code檔,這些經過編譯的檔案與函式可以運行的更快。

第三方程式庫

除了官方內建的程式庫之外,Python還有大量的第三方套件來支援,這使得我們不用重新發明輪子,即可使用前人的心血結晶來幫助我們完成任務,但是這些套件究竟放在哪裡呢?而我們又該如何來使用他們呢?請看本章的介紹與說明。

PyPI

PyPI是Python Package Index的縮寫,這是Python的第三方套件集中地,目前蒐集了超過五萬個的第三方套件,幾乎所有能想像到的功能,都可以在這找到合適的套件。所以我們有必要介紹一個方便強大的套件管理程式-pip,它能夠利用簡單的指令和步驟幫助我們從PyPI上下載想要的套件並作妥善的安裝,同時也能很方便地管理他們。

Python的套件管理程式-pip

pip是Python的套件管理工具,它集合下載、安裝、升級、管理、移除套件等功能,藉由統一的管理,可以使我們事半功倍,更重要的是,也避免了手動執行上述任務會發生的種種錯誤。

pip的安裝非常簡單,請前往pip的官方文件網站:

在install pip章節可以找到一個名為get-pip.py的檔案,讀者可以將內容複製到編輯器上再另存新檔,接著在終端機中切換到get-pip.py的目錄並執行:

$ python get-pip.py

便可以順利安裝pip囉。

上述方法是作者認為最簡單且最通用的作法,get-pip.py目前支援了CPython直譯器的2.6、2.7、3.1、3.2、3.3和3.4版本,也支援Mac OS、Linux和Windows作業系統。另外,在最新版本的Python安裝包中,pip預設會被安裝到電腦上。

當然對於一些Linux的發行版本而言,使用套件管理程式是更快的方式:

$ sudo apt-get install python-pip (apt工具)
$ sudo yum install python-pip     (yum工具)

更新pip也非常容易:

$ pip install -U pip           (Linux & Mac)
$ python -m pip install -U pip (Windows)

我們可以用list來列出目前有安裝的套件:

$ pip list
...(列出已安裝的套件及其版本)...

假設我們現在想要安裝科學計算套件Numpy,我們可以用install指令來幫助我們:

$ pip install numpy

要解除安裝可以用uninstall:

$ pip uninstall numpy

search指令可以幫助我們在線上找尋相關的套件:

$ pip search numpy
...(列出跟numpy有關的套件)...

help指令可以幫助我們了解pip的使用方式或某個套定指令的使用方式:

$ pip help
...(列出pip的使用方式和指令)...
$ pip help search
...(列出search指令的使用方式)...

常用套件簡介

在這個小節,我們會列出列出一些有名、有用或有趣的第三方套件,而這些套件可以單獨使用或是配合Django來完成更強大的功能,令人高興的是,他們都可以從pip直接安裝:

網站框架

套件名稱 簡述
Django 完整而強大的Web框架,也就是這本書介紹的內容囉
Pyramid 另一個完整強大的web框架
web2py Google app engine預設使用的框架
flask 相較於前三個是輕量的網站框架

圖片處理

套件名稱 簡述
PIL 可對圖片進行縮放、切割、旋轉等各類操作
Pillow 早先大家使用PIL,但年久失修後,出了一個fork的版本,就是Pillow

科學計算

套件名稱 簡述
Numpy 支援非常多的科學計算,包含矩陣運算、線性代數、傅立葉轉換等。可說是集大成者,大多數科學計算套件皆有使用
Matplotlib 可以畫出各種圖型如長條圖、分佈圖、立體圖等
pandas 提供特殊資料結構,具有數據處理和資料分析的功能
scikit-learn 機器學習的套件,包含內建的分群分類計算、回歸、統計等功能

命令列操作及遠端登入

套件名稱 簡述
fabric 可以直接撰寫shell命令,透過fabric執行,也支援遠端登入和自定義shell命令
paramiko 提供遠端登入和部分指令呼叫的功能

測試

套件名稱 簡述
django-nose 更多選擇及設定的Django測試套件,也可產生更詳盡的資訊

網路爬蟲

套件名稱 簡述
Scrapy Python爬蟲框架之一,可以輕易的與Django合作

文件剖析器

套件名稱 簡述
beautifulsoup 可以處理HTML、XML等標記檔案
lxml 可以處理HTML、XML等標記檔,使用xpath選取內容

自然語言處理

套件名稱 簡述
nltk 理論基礎及功能很強大的語言處理套件,但相對低階,需花一些時間熟悉才能流利使用
textblob 較高階的分詞、分句、語言分析工具
jieba 針對中文的分詞、分句、語言分析工具

網路請求用戶端

套件名稱 簡述
requests 可以模擬各種網路請求,如:get、post、put、delete等
pycurl 看名字便知道是在Linux、Unix系統上的命令:curl的python版本

背景程序、定時任務

套件名稱 簡述
celery 可輕易地編寫、呼叫非同步及背景程序,或是執行定時任務(cronjob)

資料庫介接

套件名稱 簡述
mysql-python MySQL資料庫介接套件,Django連接MySQL時預設使用的套件
psycopg2 PostgreSQL資料庫介接套件,Django連接PostgreSQL時預設使用的套件
pymongo MongoDB資料庫介接套件

上傳自己的套件

我們看了、用了那麼多別人寫的套件,自己會不會很想寫一個呢?本章前面的內容已經足夠讓大家了解如何自己撰寫一個套件並在本地端使用,但是我們要如何將這個套件分享給全世界呢?那當然就是要把套件上傳到PyPI囉!(這樣子所有人都可以用pip來下載和安裝你的套件呢)。這個小節就是要教大家怎麼作。

如果打算要上傳自己的套件,那要先去PyPI上註冊取得帳號跟密碼喔。

首先,大家要知道,如果自己的Python專案不只想要能從現行或相對的資料夾中匯入,而想要能夠安裝到Python環境中,一定要在專案的目錄底下撰寫setup.py檔。這邊針對還要上傳到PyPI,來客製化我們的setup.py,我們先來檢視一下一個待上傳的專案結構和和我們要加入的幾個設定檔位置:

MyProject/
├── README
├── pkgA
│   ├── __init__.py
│   ├── modA_1.py
│   └── modA_2.py
├── pkgB
│   ├── __init__.py
│   └── modB.py
├── runner
├── .pypirc  # 加入.pypirc
└── setup.py  # 加入setup.py

我們注意到原本該專案底下有兩個套件pkgApkgB(通常我們一個專案裡面會有數個套件,而我們在上傳專案的同時要將所屬的套件全數上傳),裡面分別有數個模組跟標示其為套件結構的__init__.py。接著我們會有一個說明檔README(用來介紹該專案的結構與使用方式,在此便不細談)和一個執行檔(整個專案的執行腳本碼)runner

接著我們要在原本的專案中加入兩個設定檔,分別是setup.py.pypirc檔,我們會逐一介紹這些檔案該如何撰寫。

首先來看到setup.py:

setup.py
from distutils.core import setup

setup(
    name = 'MyProject',
    packages = ['pkgA', 'pkgB'],
    scripts = ['runner'],
    version = '1.0',
    description = 'My first project',
    author = 'dokelung',
    author_email = 'dokelung@gmail.com',
    keywords = ['Good Project'],
    classifiers = [],
)

我們必須要從distutils.core(distutils是Python內建的套件)中匯入setup函式,此函式會幫助我們進行安裝,讓我們來了解一下此函式中每個參數的意義:

欄位名稱 描述
name 專案名稱(與專案目錄同名)
packages 要安裝的套件名稱
scripts script名稱,通常代表一個執行檔,不一定有
version 版本
description 專案描述
author 作者
author_email 作者信箱
keywords 這個專案的一些關鍵字

這邊稍微解釋一下scripts,這邊要寫在scripts裡的是整個專案的執行檔,他可能用到了專案裡面的套件。為了要將該檔案同時也裝到使用者的系統上,我們需要把他也標註上去,否則後面我們利用pip安裝的時候就只會安裝package而不會安裝執行檔了。而這邊所謂對執行檔的安裝,其實也就是把指定的scripts放到一個可執行路徑裡,例如/usr/bin/中,如此使用者在安裝完後可在任何地方運行該script(其實我們能夠指定安裝的路徑,但如果只給script名稱,那他會被放在預設的位置)。這邊有一點一定要注意,script的名字千萬不要跟他要匯入的pakcage同名了,這會導致一些匯入上的失誤。

至此,已經擁有一個漂亮的安裝檔了(同時也能支援PyPI發佈)。

接著,我們來看看.pypirc檔,唯有建立此設定檔才能讓我們傳東西到PyPI上面:

.pypirc
[distutils]
index-servers =
    pypi 

[pypi] 
repository: https://pypi.python.org/pypi
username: (此處填帳號)
password: (此處填密碼)

如果是Windows的使用者,請打開終端機(命令提示字元),進行環境變數的設定:

set HOME=C:\Users\Owner\

接著將我們在C槽的使用者資料夾(其實就是C:\Users)裡面新增一個子目錄Owner,把我們的.pipyrc複製一份放到該資料夾下,就算設定完成囉。

如果是Linux或是Mac的使用者,也請將.pypirc複製到家目錄底下:

$ cp .pypirc ~/.pypirc

上述設定檔備妥後,就到了最後一個階段,首先註冊:

$ python setup.py register -r pypi

接著上傳:

$ python setup.py sdist upload -r pypi

太好了,你成功的讓全世界都能看到你的作品了,上PyPI看看你的package頁面吧。終於,我們嘗到了甜美的果實,緊接著利用pip下載我們的專案(和裡面的套件)並安裝到自己的電腦看看:

$ pip install MyProject

如果讀者有用pip在自己的電腦上安裝了上傳的專案,該專案底下的套件就可以在本機端任何地方匯入了。

然後你就可以昭告天下,你也是Python的貢獻者了。

虛擬環境

接下來我們要向大家介紹虛擬環境,在正式開始之前呢,讓我們看看兩個情境:

情境一:如果同時有多個Python專案在進行,而每個專案需要的環境都不同(比如說,套件所需的版本不同),總不可能把全部的環境都混在一起(這一定會造成混亂的),當然我們也不可能為了每個專案各弄一台電腦!

情境二:有十個人一起開發同一個大型的專案,要怎麼確保這十個人的開發環境都相同呢? a使用Windows電腦,b使用Linux電腦,c則是使用Mac,這樣怎麼一起合作開發一個專案呢?

其中有一個解決方法就是虛擬環境,Python的虛擬環境可以在同一個系統上建立各自"獨立"且"乾淨"的開發環境,讓每個專案的套件不會相互覆蓋或影響,也確保同一個專案裡的開發人員能以相同的環境進行開發,免去相依性或衝突的問題,而可以更專心在開發或維護的工作上,這些優點讓虛擬環境成為開發者常用的工具。當然,在Python中,虛擬環境也有不同套件可以選擇,後面我們要簡介的兩個虛擬環境套件分別是virtualenvvirtualenvwrapper,接著就來看看該怎麼使用吧!

使用virtualenv

首先,讓我們用pip來安裝virtualenv吧:

$ pip install virtualenv

安裝完成後,要建立新的虛擬環境很簡單,我們先切換目錄到想要建立虛擬環境的位置,接著只需要執行virtualenv 虛擬環境名稱,便會出現類似下面的資訊(假設要建立的虛擬環境取名為test_env):

$ virtualenv test_env
New python executable in test_env/bin/python
Installing setuptools, pip...done.

我們在當前的位置可以看到新建的test_env目錄,其中包含了binlibinclude三個資料夾,這便是我們的虛擬環境了。環境建立好之後,我們得要啟動他,只要執行:

$ source test_env/bin/activate
(test_env)$

如果讀者用的是Windows的話,建立起來的虛擬環境底下應該會包含了Include、Lib、Scripts三個目錄,我們要啟動該環境只要去執行Scripts底下的activate就可以了:test_env\Scripts\activate

就會發現現在的提示字符(prompt)換成了虛擬環境的提示符,該提示符使用了括號括起了啟動的虛擬環境名稱。這時可以來驗證一下,當前的環境是不是有別於原本系統的環境(我們想知道我們是不是已經踏入世界了),執行pip list看一下有什麼套件,是不是和系統層的套件不一樣呢?神奇吧!一個新的、乾淨的、獨立的開發環境就此誕生。

我們可以在這個環境底下使用Python shell或是運行Python腳本碼,甚至在此環境底下開發Django都沒問題,只要記得在工作前進入虛擬環境就可以了。至於退出也很簡單,只要執行deactivate便可關閉虛擬環境,回到系統層,如下所示:

(test_env)$ deactivate
$

如果再也用不到這個虛擬環境,那麼就直接將test_env目錄刪除,便可以移掉這個環境的全部囉!

使用virtualenvwrapper

在Windows底下使用wirtualenvwrapper有點複雜,甚至要動用Windows的powershell,我們不建議讀者這麼作,但如果有興趣的話,可以參考http://docs.python-guide.org/en/latest/dev/virtualenvs/裡面的教學。

接著讓我們來試試另一個套件virtualenvwrapper,一樣用pip安裝:

$ pip install virtualenvwrapper

接著需宣告一個WORKON_HOME在環境變數裡,這樣virtualenvwrapper才能參照這個位置建立虛擬環境,通在會指定在家目錄下:

$ export WORKON_HOME=$HOME/.virtualenvs

接著再執行virutalenvwrapper的執行檔或腳本:

$ source /usr/local/bin/virtualenvwrapper.sh

如果不想每次手動執行的話,可以將加入WORKON_HOME參數執行腳本的動作寫入.bashrc等設定檔裡,每次開啟終端機時便會自動執行。

~/.bashrc
...
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh

接著就可以來新建虛擬環境了,執行mkvirtualenv 虛擬環境名稱後便會新建並直接啟動這個虛擬環境:

$ mkvirtualenv test_env
New python executable in test_env/bin/python
Installing setuptools, pip...done.
(test_env)$

但如果在下次開啟新的終端機要怎麼啟動呢? 就靠workon指令,而且workon指令有自動補齊功能會列出目前所有的虛擬環境,簡單操作如下:

$ workon (然後按一下TAB)
test_env    test_env2
$ workon test_env
(test_env)$

而退出則和virtualenv相同,執行deactivate即可:

(test_env)$ deactivate
$

如果想要刪掉現有的環境,則執行rmvirtualenv 虛擬環境名稱便可以完成:

$ rmvirtualenv test_env
Removing test_env...
$ workon (然後按一下TAB)
test_env2

virtualenv另外有提供列出虛擬環境(lsvirtualenv)、複製虛擬環境(cpvirtualenv)、快速切換至虛擬環境或套件的目錄(cdvirtualenv)、對所有環境操作(allvirtualenv)等附加的功能,在此不再贅述,如有需要請參考線上文件。

使用虛擬環境來解決問題

我們回到剛剛的兩個情境,虛擬環境究竟是怎麼幫我們解決問題的呢?

先看看情境一,我們不需要為每個專案都準備一個系統,但我們為每個專案都準備一個虛擬環境,當我今天要開發專案A的時候,我們切進專案A的虛擬環境中,不論是安裝套件或是運行代碼都在虛擬環境A中完成,當結束工作後,退出虛擬環境。而開發另外一個專案的時候也是如此,簡單來說,我現在要開發哪個專案、需要哪個環境,我就進入相應的虛擬環境中。

那情境二的解決也非常簡單,我們可以將建立好的虛擬環境,統一複製配給參與專案的每一個人,方法有:一、打包處擬環境的目錄,或是二、通常會使用pip freeze指令將套件列表輸出在一個requirements.txt檔案,其他人再依檔案內容安裝套件。另外有兩點要注意,第一點是每個人的電腦都需要安裝過虛擬環境套件。第二點是當某個人的虛擬環境有所變動時(比如說新安裝了某套件或是套件升級等),所有人的虛擬環境也需要做相應的更新。

最後,如果可以的話,我們希望讀者在演示範例或自行開發的時候能夠使用虛擬環境,這樣好習慣的養成對未來會大有幫助的。

當然,懶得這樣做或是為了學習上的方便,我們不會要求一定要使用虛擬環境,本書中的所有內容是否使用虛擬環境都是適用的。

本章小結

本章向讀者介紹了模組和套件的概念,透過這樣對程式碼作分層式的管理,再加上名稱空間的輔助,可以使我們的程式管理和運用更清晰明瞭。同時我們也介紹了PyPI和pip工具,往後讀者們可以依據需要去下載相應的套件(我們要學習的Django也可以使用pip下載喔),讓我們的網站或是開發更加強大。最後,我們也介紹了虛擬環境的概念,希望能夠幫助讀者擁有一個好的開發環境。至此,我們對於Python的介紹也告一段落了,準備了那麼久的時間,是時候讓我們的主人公-Django登場了,請看下一章!

← 專案整理與發佈-從Github到PyPI 一校補充 →
 
comments powered by Disqus