CrazyWing:Python自動化運維開發實戰 十5、Python模塊

導語:

模塊讓你可以有邏輯地組織Python代碼段。把相關的代碼分配到一個模塊裏能讓你的代碼更好用,更易懂。模塊也是Python對象,具備隨機的名字屬性用來綁定或引用。簡單地說,模塊就是一個保存了Python代碼的文件。模塊能定義函數,類和變量。模塊裏也能包含可執行的代碼。python

相關站點:

https://pypi.python.org/pypi/
PyPI(Python Package Index,PyPI) python包索引
爲Internet上的第三方Python模塊提供一個集中的存儲庫linux

製做模塊

模塊結構和佈局:
用模塊來合理組織你的 Python 代碼是簡單又天然的方法。你應該創建一種統一且容易閱讀的結構,並將它應用到每個文件中去。
下面就是一種很是合理的佈局,一個典型模塊的內部結構:shell

# (1) 起始行(Unix) 
    # (2) 模塊文檔
    # (3) 模塊導入
    # (4) 變量定義
    # (5) 類定義
    # (6) 函數定義
    # (7) 主程序

例:
一個叫作aname的模塊裏的Python代碼通常都能在一個叫aname.py的文件中找到。vim

下例是個簡單的模塊mod.py:app

[root@wing python]# cat mod.py
#!/usr/bin/env python
# coding=utf8
'''
這是一個模塊實例
'''
import sys,os
name="wing"

def hello():
    print "hello world"

if __name__ =="__main__":
    hello()

使用模塊:
In [1]: import mod

In [2]: mod.hello()
hello world

In [4]: print mod.__doc__
這是一個模塊實例

In [5]: print mod.name
wing

import():

查詢模塊是內建模塊仍是屬於某一個模塊文件python2.7

In [5]: __import__("sys")
Out[5]: <module 'sys' (built-in)>

In [3]: __import__("os")
Out[3]: <module 'os' from '/usr/lib64/python2.7/os.pyc'>

In [4]: __import__("os").__file__
Out[4]: '/usr/lib64/python2.7/os.pyc'

內建變量name

可使用兩種方法調用main函數,可是每次在python解釋器裏第一次import模塊pysysinfo_func時都會執行main函數若是又想能夠把模塊當腳本同樣在命令行總體執行,又想在其餘腳本調用模塊內單獨的某一個函數,可使用第二種方式編輯器

#vim pysysinfo_func.py
#!/usr/bin/env python
import subprocess
def uname_func():
    uname = "uname"
    uname_arg = "-a"
    print "Gathering system information with %s command:\n" % uname
    subprocess.call([uname,uname_arg])

def disk_func():
    diskspace = "df"
    diskspace_arg = "-Th"
    print "Gathering diskspace information with %s command:\n" % diskspace
    subprocess.call([diskspace,diskspace_arg])

def main():
    uname_func()
    disk_func()

#第一種方式:
main()

#第二種方式:
if __name__ == "__main__":
    main()   

第一種方式的結果以下:會在導入模塊的時候執行main函數
In [1]: import pysysinfo_func
Gathering system information with uname command:

Linux vm2.up.com 2.6.32-358.el6.x86_64 #1 SMP Tue Jan 29 11:47:41 EST 2013 x86_64 x86_64 x86_64 GNU/Linux
Gathering diskspace information with df command:

Filesystem    Type    Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root
              ext4     18G  4.1G   13G  25% /
tmpfs        tmpfs    565M  224K  565M   1% /dev/shm
/dev/sda1     ext4    485M   34M  427M   8% /boot
/dev/sr0   iso9660    3.5G  3.5G     0 100% /mnt

第二種方式的結果以下:
In [1]: import pysysinfo_func    //不會在導入模塊的時候執行main函數

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

python中__name__的使用
1. 若是模塊是被導入,__name__的值爲模塊名字
2. 若是模塊是被直接執行,__name__的值爲’__main__’

Py1.py
#!/usr/bin/env python
def test():
        print    '__name__ = ',__name__

if __name__ == '__main__':
        test()

Py2.py
#!/usr/bin/env python
import Py1.py
def test():
         print  '__name__ = ',__name__

if __name__ == '__main__':
         test()
         print ‘Py1.py __name__ = ’,Py1.__name__

執行結果:
        __name__=__main__
        Py1.py __name__=Py1

經過結果能夠知道,Py2.py直接執行,那麼內建變量__name__的值爲__main__,不然爲
模塊的名字,經過這個特性能夠
在if語句裏面添加測試代碼,能夠提升減小BUG,提升程序的健壯性。
if __name__ == '__main__':
       test()

查看模塊:

查看模塊存放位置

經過查看模塊存放路徑就知道咱們本身製做的模塊應該放在哪一個位置ide

查看python默認的模塊存放路徑。 函數

>>> import sys
>>> sys.path
['', '/usr/local/python27/lib/python27.zip', '/usr/local/python27/lib/python2.7', '/usr/local/python27/lib/python2.7/plat-linux2', '/usr/local/python27/lib/python2.7/lib-tk', '/usr/local/python27/lib/python2.7/lib-old', '/usr/local/python27/lib/python2.7/lib-dynload', '/usr/local/python27/lib/python2.7/site-packages']
>>>

列表內的第一個元素''表示當前工做目錄,也就是說模塊在當前目錄下也可以使用默認存放模塊的目錄是:/usr/local/python27/lib/python2.7/佈局

查看模塊內定義的各類標識符號

dir()函數
dir()函數返回一個排好序的字符串列表,內容是一個模塊裏定義過的名字。
返回的列表容納了在一個模塊裏定義的全部模塊,變量和函數。

實例:

#!/usr/bin/python
import math
content = dir(math)
print content;

輸出結果:
['__doc__', '__file__', '__name__', 'acos', 'asin', 'atan', 
'atan2', 'ceil', 'cos', 'cosh', 'degrees', 'e', 'exp', 
'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log',
'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 
'sqrt', 'tan', 'tanh']

在這裏,特殊字符串變量name指向模塊的名字,file指向該模塊的導入文件名。

調用模塊

import 語句

想使用Python模塊,只需在另外一個源文件裏執行import語句
語法以下:
import module1[, module2[,... moduleN]
當解釋器遇到import語句,若是模塊在當前的搜索路徑就會被導入。

搜索路徑:
是一個解釋器會先進行搜索的全部目錄的列表。如想要導入模塊support.py,須要把命令放在腳本的頂端

#!/usr/bin/python
    # -*- coding: UTF-8 -*-
    # 導入模塊
    import support 
    # 如今能夠調用模塊裏包含的函數了
    support.print_func("Zara") 

以上實例輸出結果:
    Hello : Zara
一個模塊只會被導入一次,無論你執行了多少次import。這樣能夠防止導入模塊被一遍又一遍地執行。

From…import 語句

Python的from語句讓你從模塊中導入一個指定的部分到當前命名空間中。語法以下:
from modname import name1[, name2[, ... nameN]]
例如,要導入模塊fib的fibonacci函數,使用以下語句:
from fib import fibonacci
這個聲明不會把整個fib模塊導入到當前的命名空間中,它只會將fib裏的fibonacci單個引入到執行這個聲明的模塊的全局符號表。

From…import * 語句

把一個模塊的全部內容全都導入到當前的命名空間也是可行的,只需使用以下聲明:
from modname import *
這提供了一個簡單的方法來導入一個模塊中的全部項目。然而這種聲明不應被過多地使用。

定位模塊

當你導入一個模塊,Python解析器對模塊位置的搜索順序是:

• 當前目錄
• 若是不在當前目錄,Python 則搜索在 shell 變量 PYTHONPATH 下的每一個目錄。
• 若是都找不到,Python會察看默認路徑。UNIX下,默認路徑通常爲/usr/local/lib/python/。

模塊搜索路徑存儲在system模塊的sys.path變量中。變量裏包含當前目錄,PYTHONPATH和由安裝過程決定的默認目錄。

PYTHONPATH變量
做爲環境變量,PYTHONPATH由裝在一個列表裏的許多目錄組成。PYTHONPATH的語法和shell
變量PATH的同樣。
在Windows系統,典型的PYTHONPATH以下:
set PYTHONPATH=c:\python20\lib

在UNIX系統,典型的PYTHONPATH以下:
set PYTHONPATH=/usr/local/lib/python

python解釋器開啓時調用模塊

正常狀況下使用python解釋器,使用模塊的方法時須要導入模塊,一些本身比較經常使用的模塊好比os、process每次開始python解釋器都得從新調用,下面的方法能夠爲你解除痛苦。

很是簡單,只需設置一個變量,變量的值爲某個.py文件的路徑,在.py文件內設置預先想要導入的模塊

# export PYTHONSTARTUP=/a.py

# cat /a.py 
import os
import subprocess

[root@vm2 ~]# python
>>> os.system("ls")       //能夠看到測試的OS模塊的時候能夠直接使用,無需事先導入
模塊OS
anaconda-ks.cfg  Documents    install.log.syslog  Public
a.py         Downloads    Music       Templates
咱們能夠利用上面得方法把tab鍵功能寫入模塊內事先導入

重載模塊

reload()函數
當一個模塊被導入到一個腳本,模塊頂層部分的代碼只會被執行一次。所以,若是你想從新執行模塊裏頂層部分的代碼,能夠用reload()函數。該函數會從新導入以前導入過的模塊。
語法以下:
reload(module_name)
在這裏,module_name要直接放模塊的名字,而不是一個字符串形式。

好比想重載hello模塊,以下:
reload(hello)

1.同一個模塊導入,第一次代碼所有運行,第二次不少的代碼都不運行的,其實中間只是重複執行

2.嘗試在第一次導入後,修改源文件,而後第二次導入,結果跟第一次同樣。

緣由:

導入操做的開銷很是大,它把文件先編譯成字節碼,而後再導pvm(python virtual machine)上去執行,在編譯的過程當中,消耗資源很是多,因此,導入操做只編譯執行一次,第二次只是重複執行,再也不編譯。
若是想再次執行完整的代碼,就須要reload()這個函數,他會把源代碼從新載入,而後執行一遍,可是在執行reload前,必須保證已經import那個模塊。
注意:在python3裏,執行reload前,請先執行from imp import reload,由於reload在python3裏已經再也不是內置函數。

例:

1.編寫模塊a.py
#!/usr/bin/env python
print "hello world"

2.進入Ipython倒入模塊
In [1]: import a
hello world    第一次導入結果有輸出

In [2]: import a
                    第二次導入結果就沒有輸出了
In [3]: import a
                    修改源文件後再次導入仍然沒有輸出結果
In [4]: 
必須的用reload()重載模塊才行

發佈本身的模塊

以以前處理嵌套列表的代碼爲例,把他作成能夠發給別人使用的模塊

1.建立父目錄:
#mkdir /nester

2.準備源代碼文件:
#vim /nester/nester.py
#!/usr/bin/env python
#coding=utf-8
"這是模塊文檔字符串"
def print_list(name):
"這是函數文檔字符串"
for each_item in name:
if isinstance(each_item,list):
print_list(each_item)
else:
print each_item

3.準備setup.py文件:

vim /nester/setup.py

#!/usr/bin/env python
    from distutils.core import setup
    setup(
        name = 'nester',
        version = '1.0.0',
        py_modules = ['nester'],
        author = 'wing',
        author_email = '276267003@qq.com',
        url = 'www.fklinux.com',
        description = 'A simple printer of nested lists',
    )

4.構建發佈文件:

cd /nester

# python setup.py sdist

5.構建成功以後/nester目錄下會出現dist目錄,dist目錄下會出現構建好的模塊打包文件,這個文件就能夠發給別人使用了
[root@host nester]# ls dist/
nester-1.0.0.tar.gz

6.測試安裝模塊:
#tar xvzf nester-1.0.0.tar.gz
#cd nester-1.0.0
#python setup.py install
#python

import nester //其實到這裏,若是你能導入模塊成功的話,恭喜你,^_^說明你的模塊兒沒問題了,下面是這個模塊的具體使用
a=[1,2,3,[4,5,[6,7]]]
nester.print_list(a)
1
2
3
4
5
6
7

Python中的包

包是一個分層次的文件目錄結構,它定義了一個由模塊及子包,和子包下的子包等組成的Python的應用環境。

例子:

1.建立目錄Phone,做爲包名
#mkdir /Phone   

2.分別建立模塊文件pots.py、lsdn.py和G3.py
#cat /Phone/pots.py
#!/usr/bin/python
def Pots():
   print "I'm Pots Phone"

#cat /Phone/Isdn.py
#!/usr/bin/python
def Lsdn():
   print "I'm lsdn Phone"

#cat /Phone/G3.py  
#!/usr/bin/python
def G3():
   print "I'm G3 Phone"

3.在/Phone目錄下建立文件 __init__.py:
#cat /Phone/__init__.py
from Pots import Pots
from Isdn import Isdn
from G3 import G3 

4.使用包:
#!/usr/bin/python
# 導入 Phone 包
import Phone

Phone.Pots()
Phone.Isdn()
Phone.G3() 

輸出結果:
I'm Pots Phone
I'm 3G Phone
I'm ISDN Phone 
如上,爲了舉例,只在每一個文件裏放置了一個函數,但其實你能夠放置許多函數。你也能夠在這些文件裏定義Python的類,而後爲這些類建一個包。

製做tab補全模塊:

若是在python編輯器裏tab鍵不能補全,能夠本身定義一個tab.py程序,而後看成模塊導入就可使用tab鍵補全了

#cat tab.py
#!/usr/bin/env python
import sys,readline,rlcompleter,os  
readline.parse_and_bind('tab: complete')
histfile = os.path.join(os.environ['HOME'],'.pythonhistory')

把本身編寫的tab模塊拷貝到默認模塊目錄下,若是不拷貝到默認位置也可使用,不過須要在進入python shell的當前目錄下存放tab.py
#mv tab.py /usr/local/python27/lib/python2.7/

tab模塊使用:

import tab

上面的方式在使用tab模塊的時候跟使用其餘模塊同樣每次都須要手動導入,若是你像我同樣比較懶^_^,可使用下面的方法,在啓動python shell的時候就自動導入咱們想讓他導入的模塊

python shell自動導入模塊:

1.建立一個腳本文件:

cat /root/.startup.py

#!/usr/bin/evn python
    import tab
    print "module loaded"

2.設置PYTHONSTARTUP環境變量:
#export PYTHONSTARTUP=/root/.startup.py //如何永久生效?你懂的

3.測試:

python

Python 2.7.10 (default, Dec 13 2016, 10:54:54) 
    [GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    module loaded
相關文章
相關標籤/搜索