正文如下:
模塊
在計算機程序的開發(fā)過程中刊橘,隨著程序代碼越寫越多鄙才,在一個文件里代碼就會越來越長,越來越不容易維護促绵。
為了編寫可維護的代碼攒庵,我們把很多函數分組
,分別放到不同的文件里败晴,這樣浓冒,每個文件包含的代碼就相對較少,很多編程語言都采用這種組織代碼的方式尖坤。在Python中稳懒,一個.py
文件就稱之為一個模塊
(Module)。
使用模塊有什么好處慢味?
最大的好處是大大提高了代碼的可維護性场梆。其次,編寫代碼不必從零開始纯路。當一個模塊編寫完畢或油,就可以被其他地方引用。我們在編寫程序的時候驰唬,也經常引用其他模塊顶岸,包括Python內置
的模塊和來自第三方
的模塊。
使用模塊還可以避免函數名
和變量名
沖突定嗓。相同名字的函數和變量完全可以分別存在不同的模塊中蜕琴,因此,我們自己在編寫模塊時宵溅,不必考慮名字會與其他模塊沖突凌简。但是也要注意,盡量不要與內置函數名字沖突恃逻。點這里查看Python的所有內置函數雏搂。
你也許還想到,如果不同的人編寫的模塊名相同怎么辦寇损?為了避免模塊名沖突凸郑,Python又引入了按目錄來組織模塊的方法,稱為包
(Package)矛市。
舉個例子芙沥,一個abc.py
的文件就是一個名字叫abc
的模塊,一個xyz.py
的文件就是一個名字叫xyz
的模塊。
現在而昨,假設我們的abc
和xyz
這兩個模塊名字與其他模塊沖突了救氯,于是我們可以通過包來組織模塊,避免沖突歌憨。方法是選擇一個頂層包名着憨,比如mycompany
,按照如下目錄存放:
mycompany
├─ __init__.py
├─ abc.py
└─ xyz.py
引入了包以后务嫡,只要頂層的包名不與別人沖突甲抖,那所有模塊都不會與別人沖突。現在心铃,abc.py
模塊的名字就變成了mycompany.abc
准谚,類似的,xyz.py
的模塊名變成了mycompany.xyz
于个。
請注意氛魁,每一個包目錄下面都會有一個
__init__.py
的文件暮顺,這個文件是必須存在的厅篓,否則,Python就把這個目錄當成普通目錄捶码,而不是一個包羽氮。init.py可以是空文件,也可以有Python代碼惫恼,因為__init__.py
本身就是一個模塊档押,而它的模塊名就是mycompany
。
類似的祈纯,可以有多級目錄令宿,組成多級層次的包結構。比如如下的目錄結構:
mycompany
├─ web
│ ├─ __init__.py
│ ├─ utils.py
│ └─ www.py
├─ __init__.py
├─ abc.py
└─ xyz.py
文件www.py
的模塊名就是mycompany.web.www
腕窥,兩個文件utils.py
的模塊名分別是mycompany.utils
和mycompany.web.utils
粒没。
自己創(chuàng)建模塊時要注意命名,不能和Python自帶的模塊名稱沖突簇爆。例如癞松,系統(tǒng)自帶了
sys
模塊,自己的模塊就不可命名為sys.py
入蛆,否則將無法導入系統(tǒng)自帶的sys
模塊响蓉。
使用模塊
Python本身就內置
了很多非常有用的模塊,只要安裝完畢哨毁,這些模塊就可以立刻使用枫甲。
我們以內建的sys
模塊為例,編寫一個hello
的模塊:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
' a test module '
__author__ = 'Michael Liao'
import sys
def test():
args = sys.argv
if len(args)==1:
print('Hello, world!')
elif len(args)==2:
print('Hello, %s!' % args[1])
else:
print('Too many arguments!')
if __name__=='__main__':
test()
第1
行和第2
行是標準注釋,第1行注釋可以讓這個hello.py文件直接在Unix/Linux/Mac上運行想幻,第2行注釋表示.py
文件本身使用標準UTF-8
編碼软能;
第4行是一個字符串,表示模塊的文檔注釋
举畸,任何模塊代碼的第一個字符串都被視為模塊的文檔注釋查排;
第6行使用__author__
變量把作者寫進去,這樣當你公開源代碼后別人就可以瞻仰你的大名抄沮;
以上就是Python模塊的標準文件模板跋核,當然也可以全部刪掉不寫,但是叛买,按標準辦事肯定沒錯砂代。
后面開始就是真正的代碼部分。
你可能注意到了率挣,使用sys
模塊的第一步刻伊,就是導入該模塊:
import sys
導入sys
模塊后,我們就有了變量sys
指向該模塊椒功,利用sys
這個變量捶箱,就可以訪問sys
模塊的所有功能。
sys
模塊有一個argv
變量动漾,用list
存儲了命令行的所有參數丁屎。argv
至少有一個元素,因為第一個參數永遠是該.py文件的名稱旱眯,例如:
運行python3 hello.py
獲得的sys.argv
就是['hello.py']晨川;
運行python3 hello.py Michael
獲得的sys.argv
就是['hello.py', 'Michael]。
最后删豺,注意到這兩行代碼:
if __name__=='__main__':
test()
當我們在命令行運行hello
模塊文件時共虑,Python解釋器把一個特殊變量__name__
置為__main__
褐奴,而如果在其他地方導入該hello
模塊時缆八,if
判斷將失敗痹屹,因此貌虾,這種if測試可以讓一個模塊通過命令行運行時執(zhí)行一些額外的代碼溶褪,最常見的就是運行測試吐葵。
我們可以用命令行運行hello.py
看看效果:
$ python3 hello.py
Hello, world!
$ python hello.py Michael
Hello, Michael!
如果啟動Python
交互環(huán)境逢慌,再導入hello模塊:
$ python3
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 23 2015, 02:52:03)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import hello
>>>
導入時妙啃,沒有打印Hello, word!
疾党,因為沒有執(zhí)行test()
函數音诫。
調用hello.test()
時,才能打印出Hello, word!:
>>> hello.test()
Hello, world!
作用域
在一個模塊中雪位,我們可能會定義很多函數和變量竭钝,但有的函數和變量我們希望給別人使用,有的函數和變量我們希望僅僅在模塊內部使用。在Python中香罐,是通過_
前綴來實現的卧波。
正常的函數和變量名是
公開的
(public),可以被直接引用庇茫,比如:abc
港粱,x123
,PI
等旦签;類似
__xxx__
這樣的變量是特殊變量
查坪,可以被直接引用,但是有特殊用途宁炫,比如上面的__author__
偿曙,__name__
就是特殊變量,hello
模塊定義的文檔注釋也可以用特殊變量__doc__
訪問羔巢,我們自己的變量一般不要用這種變量名望忆;類似
_xxx
和__xxx
這樣的函數或變量就是非公開的
(private),不應該被直接引用竿秆,比如_abc启摄,__abc等;
之所以我們說袍辞,private
函數和變量“不應該”被直接引用鞋仍,而不是“不能”被直接引用,是因為Python
并沒有一種方法可以完全限制訪問private
函數或變量搅吁,但是,從編程習慣上不應該引用private
函數或變量落午。
private
函數或變量不應該被別人引用谎懦,那它們有什么用呢?請看例子:
def _private_1(name):
return 'Hello, %s' % name
def _private_2(name):
return 'Hi, %s' % name
def greeting(name):
if len(name) > 3:
return _private_1(name)
else:
return _private_2(name)
我們在模塊里公開greeting()
函數溃斋,而把內部邏輯用private
函數隱藏起來了界拦,這樣,調用greeting()
函數不用關心內部的private
函數細節(jié)梗劫,這也是一種非常有用的代碼封裝和抽象的方法享甸,即:
外部不需要引用的函數全部定義成private,只有外部需要引用的函數才定義為public
梳侨。
安裝第三方模塊
在Python中蛉威,安裝第三方模塊,是通過包管理工具pip
完成的走哺。
如果你正在使用Mac
或Linux
蚯嫌,安裝pip
本身這個步驟就可以跳過了。
如果你正在使用Windows,請參考安裝Python一節(jié)的內容择示,確保安裝時勾選了pip
和Add python.exe to Path
束凑。
在命令提示符窗口下嘗試運行pip
,如果Windows提示未找到命令栅盲,可以重新運行安裝程序添加pip
汪诉。
注意:Mac或Linux上有可能并存Python 3.x和Python 2.x,因此對應的pip命令是
pip3
谈秫。
例如摩瞎,我們要安裝一個第三方庫——Python Imaging Library
,這是Python下非常強大的處理圖像的工具庫孝常。不過旗们,PIL
目前只支持到Python 2.7,并且有年頭沒有更新了构灸,因此上渴,基于PIL
的Pillow
項目開發(fā)非常活躍喜颁,并且支持最新的Python 3稠氮。
一般來說,第三方庫都會在Python官方的pypi.python.org網站注冊半开,要安裝一個第三方庫隔披,必須先知道該庫的名稱,可以在官網或者pypi上搜索寂拆,比如Pillow的名稱叫Pillow奢米,因此,安裝Pillow的命令就是:
pip install Pillow
耐心等待下載并安裝后纠永,就可以使用Pillow了鬓长。
安裝常用模塊
在使用Python
時,我們經常需要用到很多第三方庫尝江,例如涉波,上面提到的Pillow
,以及MySQL
驅動程序炭序,Web框架Flask
啤覆,科學計算Numpy
等。用pip
一個一個安裝費時費力惭聂,還需要考慮兼容性窗声。我們推薦直接使用Anaconda,這是一個基于Python的數據處理和科學計算平臺彼妻,它已經內置了許多非常有用的第三方庫嫌佑,我們裝上Anaconda
豆茫,就相當于把數十個第三方模塊自動安裝好了,非常簡單易用屋摇。
可以從Anaconda官網下載GUI安裝包揩魂,安裝包有500~600M,所以需要耐心等待下載炮温。網速慢的同學請移步國內鏡像火脉。下載后直接安裝,Anaconda會把系統(tǒng)Path
中的python
指向自己自帶的Python
柒啤,并且倦挂,Anaconda
安裝的第三方模塊會安裝在Anaconda
自己的路徑下,不影響系統(tǒng)已安裝的Python
目錄担巩。
安裝好Anaconda后方援,重新打開命令行窗口,輸入python
涛癌,可以看到Anaconda的信息:
┌────────────────────────────────────────────────────────┐
│Command Prompt - python - □ x │
├────────────────────────────────────────────────────────┤
│Microsoft Windows [Version 10.0.0] │
│(c) 2015 Microsoft Corporation. All rights reserved. │
│ │
│C:\> python │
│Python 3.6.3 |Anaconda, Inc.| ... on win32 │
│Type "help", ... for more information. │
│>>> import numpy │
│>>> _ │
│ │
│ │
│ │
└────────────────────────────────────────────────────────┘
可以嘗試直接import numpy
等已安裝的第三方模塊犯戏。
模塊搜索路徑
當我們試圖加載一個模塊時,Python會在指定的路徑下搜索對應的.py
文件拳话,如果找不到先匪,就會報錯:
>>> import mymodule
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named mymodule
默認情況下,Python
解釋器會搜索當前目錄
弃衍、所有已安裝的內置模塊
和第三方模塊
呀非,搜索路徑存放在sys
模塊的path
變量中:
>>> import sys
>>> sys.path
['', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', ..., '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages']
如果我們要添加自己的搜索目錄,有兩種方法:
一是直接修改sys.path
镜盯,添加要搜索的目錄:
>>> import sys
>>> sys.path.append('/Users/michael/my_py_scripts')
這種方法是在運行時修改岸裙,運行結束后失效。
第二種方法是設置環(huán)境變量PYTHONPATH
形耗,該環(huán)境變量的內容會被自動添加到模塊搜索路徑中哥桥。設置方式與設置Path環(huán)境變量類似。注意只需要添加你自己的搜索路徑激涤,Python自己本身的搜索路徑不受影響。