案例1:斐波那契數列 案例2:模擬cp操做 案例3:生成8位隨機密碼
1 案例1:斐波那契數列
1.1 問題python
編寫fib.py腳本,主要要求以下:linux
輸出具備10個數字的斐波那契數列 使用for循環和range函數完成 改進程序,要求用戶輸入一個數字,能夠生成用戶須要長度的斐波那契數列
1.2 方案git
斐波那契數列就是某一個數,老是前兩個數之和,好比0,1,1,2,3,5,8。因爲輸出是一串數字,能夠用列表的結構存儲。開始時,列表中有兩個值,即0,1。而後經過循環向列表中追加元素,追加元素老是列表中最後兩個元素值之和。shell
本例使用的是列表,不能使用元組,由於列表是一個可變類型,而元組是不可變類型。各類數據類型的比較以下:vim
按存儲模型分類app
標量類型:數值、字符串dom
容器類型:列表、元組、字典ide
按更新模型分類:函數
可變類型:列表、字典code
不可變類型:數字、字符串、元組
按訪問模型分類
直接訪問:數字
順序訪問:字符串、列表、元組
映射訪問:字典
因爲循環次數是肯定的,可使用for循環。python中的for循環與傳統的for循環(計數器循環)不太同樣,它更象shell腳本里的foreach迭代。python中的for接受可迭代對象(例如序列或迭代器)做爲其參數,每次迭代其中一個元素。
for循環常常與range()函數一塊兒使用。range函數語法以下:
range([start,] stop[, step])
range函數將返回一個列表,若是列表沒有給定起始值,那麼起始值從0開始,結束值是給定的結束值的前一個值,另外還能夠設置步長值。例:
>>> range(10) #沒有給定起始值則從0開始,結束值爲9 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> range(5,10) #給定起始值,列表的第一個值就是給定的起始值 [5, 6, 7, 8, 9] >>> range(0, 10, 2) #給定步長值爲2,列出10之內的偶數 [0, 2, 4, 6, 8] >>> range(1, 10, 2) #給定起始值、步長值,列出10之內的奇數 [1, 3, 5, 7, 9]
當將腳本改爲交互式運行時,須要注意,用戶輸入的數字,python仍然將其視爲字符而不是整型數字,須要使用int()將用戶輸入作類型轉換。
在進行運算時,應使得參與運算的對象屬於同一類型,不然若是python沒法進行隱匿類型轉換將會出現異常。
>>> '30' + 3 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: cannot concatenate 'str' and 'int' objects
上面的代碼之因此出現錯誤,是由於不能將字符串與數字進行加法或拼接運算。若是但願將其拼接,可使用下面的方式:
>>> '30' + str(3) '303'
若是但願將其全做爲數字進行相加,可使用下面的方式:
>>> int('30') + 3 33
1.3 步驟
實現此案例須要按照以下步驟進行。
步驟一:編寫固定輸出的斐波那契數列
[root@py01 bin]# vim fibs.py #!/usr/bin/env python fibs = [0, 1] for i in range(8): fibs.append(fibs[-1] + fibs[-2]) print fibs
執行結果以下:
[root@py01 bin]# ./fibs.py [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
步驟二:將腳本改成交互式執行
若是但願生成用戶指定個數的數列,須要與用戶進行交互,經過raw_input()函數讀取用戶指定的長度。由於raw_input()函數讀入的數據均爲字符串,因此須要對其進行類型轉換,經過int()函數將字符串類型的數值轉換成數字類型。
爲了可以進行加法計算,須要提早擁有兩個數值。既然已經存在兩個值,那麼用戶指定數列個數後,在循環時,應該少循環兩次。
修改後的代碼以下:
[root@py01 bin]# vim fibs2.py #!/usr/bin/env python fibs = [0, 1] nums = int(raw_input('Input a number: ')) for i in range(nums - 2): fibs.append(fibs[-1] + fibs[-2]) print fibs
腳本運行結果以下:
[root@py01 bin]# ./fibs2.py Input a number: 5 [0, 1, 1, 2, 3] [root@py01 bin]# ./fibs2.py Input a number: 20 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
2 案例2:模擬cp操做
2.1 問題
編寫cp.py腳本,實現如下目標:
將/bin/ls「拷貝」到/root/目錄下 要求讀取/bin/ls後,每次讀取4096字節,依次寫入到新文件 不要修改原始文件
2.2 方案
「拷貝」一個文件,能夠想像成諒是先在目標位置建立一個空文件,而後再將源文件讀出,寫入到新文件中。
在python中打開文件的方法是open(),或者使用file(),兩個函數徹底同樣能夠進行相互替換。open的語法以下:
open(name[, mode[, buffering]])
open的第一個參數是文件名,能夠是相對路徑,也能夠是絕路徑。最後的一個參數是緩衝設置,默認狀況下使用緩衝區。硬盤是計算機系統中最慢的一個組件,若是每產生一個字符都當即寫入磁盤,那麼這種方式的工做效率將極其低下,能夠先把數據放在內存的緩衝區中,當緩衝區的數據比較多的時候,再批量寫入磁盤文件。當文件關閉的時候,緩衝區的數據也會寫入磁盤。第二個模式參數的含義以下:
>>> f = open('abc.txt', 'r') #文件不存在 Traceback (most recent call last): File "<stdin>", line 1, in <module> IOError: [Errno 2] No such file or directory: 'abc.txt' >>> f = open('/etc/hosts') >>> f.write('hello') #寫入文件時報錯,由於並不是以寫入方式打開 Traceback (most recent call last): File "<stdin>", line 1, in <module> IOError: File not open for writing >>> f = open('abc.txt', 'w') #文件不存在,首先建立了abc.txt >>> f.read() #由於以寫的方式打開,讀取時出錯 Traceback (most recent call last): File "<stdin>", line 1, in <module> IOError: File not open for reading
打開文件時並不消耗太多內存,可是將文件內容讀到變量中,會根據讀入的數據大小消耗相應的內存。例:
#首先建立一個名爲ttt.img的文件,大小爲100MB [root@py01 bin]# dd if=/dev/zero of=ttt.img bs=1M count=100 [root@py01 bin]# free –m #觀察已用內存,值爲665M total used free shared buffers cached Mem: 994 665 329 0 24 339 -/+ buffers/cache: 301 693 Swap: 4031 0 4031 [root@py01 bin]# python #從另外一終端中打開python解釋器 Python 2.6.6 (r266:84292, Oct 12 2012, 14:23:48) [GCC 4.4.6 20120305 (Red Hat 4.4.6-4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> f = open('ttt.img') #打開該文件 [root@py01 bin]# free –m #觀察已用內存並無變化 total used free shared buffers cached Mem: 994 665 329 0 24 339 -/+ buffers/cache: 301 693 Swap: 4031 0 4031 >>> data = f.read() #再回到python解釋器,讀入所有文件內容 [root@py01 bin]# free –m #觀察已用內存,增長了100MB total used free shared buffers cached Mem: 994 764 230 0 24 339 -/+ buffers/cache: 399 595 Swap: 4031 0 4031 >>> del data #回到python解釋器,刪除data變量 [root@py01 bin]# free –m #已用內存又減小了100MB total used free shared buffers cached Mem: 994 663 330 0 24 339 -/+ buffers/cache: 299 695 Swap: 4031 0 4031
爲了防止一次性讀入大文件消耗太多的內存,能夠採用循環的方式,屢次少許讀取數據。通常狀況下能夠設置每次讀取4096字節便可。
2.3 步驟
實現此案例須要按照以下步驟進行。
步驟一:編寫腳本
注意,一般文件操做有三個步驟:打開文件,處理文件,關閉文件。每每被忽略的是關閉文件,若是文件沒有正常關閉,有可能形成數據丟失。
[root@py01 bin]# vim cp.py #!/usr/bin/env python dstfile = '/root/ls' srcfile = '/bin/ls' oldf = open(srcfile) #以讀方式打開老文件 newf = open(dstfile, 'w') #以寫方式打開新文件 while True: #由於不肯定要循環多少次,設置條件永遠爲真 data = oldf.read(4096) #每次只讀入4096字節 if len(data) == 0: #若是文件已經所有讀取完畢則中斷循環 break newf.write(data) oldf.close() newf.close()
步驟二:經過md5值判斷新老文件是否徹底一致
[root@py01 bin]# ./cp.py [root@py01 bin]# md5sum /root/ls c98cff985579da387db6a2367439690a /root/ls [root@py01 bin]# md5sum /bin/ls c98cff985579da387db6a2367439690a /bin/ls [root@py01 bin]# ll /root/ls -rw-r--r--. 1 root root 117024 Jun 27 15:40 /root/ls [root@py01 bin]# chmod +x /root/ls [root@py01 bin]# /root/ls /home/ demo demo.tar.gz lost+found
md5值是文件的指紋信息,若是兩個文件的內容徹底同樣,那麼其md5值必定相同,若是兩個文件有微小的不一樣,其md5值也必定徹底不同。不過文件的權限不會影響md5值的斷定。將拷貝後的目標文件加上執行權限,就能夠像原始文件同樣的工做了。
3 案例3:生成8位隨機密碼
3.1 問題
編寫randpass.py腳本,實現如下目標:
使用random的choice函數隨機取出字符 用於密碼的字符經過string模塊得到 改進程序,用戶能夠本身決定生成多少位的密碼
3.2 方案
假定只使用大小寫字母和數字做爲密碼,這些字符能夠本身定義,不過string模塊中已有這些屬性。經過導入string模塊能夠減小代碼量,同時提升效率。
>>> import string >>> string.lowercase 'abcdefghijklmnopqrstuvwxyz' >>> string.uppercase 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' >>> string.letters 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' >>> string.digits '0123456789'
這個程序的主要思路是,首先建立一個空字符串變量用於存儲密碼,而後每次在可用字符中隨機選擇一個字符,再把該字符與變量中的字符進行拼接。
3.3 步驟
實現此案例須要按照以下步驟進行。
步驟一:編寫腳本,生成8位隨機密碼
[root@py01 bin]# vim randpass.py #!/usr/bin/env python import string import random passwd = '' passchs = string.letters + string.digits for i in range(8): passwd += random.choice(passchs) print passwd
腳本運行結果以下:
[root@py01 bin]# ./randpass.py 1U4MMBg3 [root@py01 bin]# ./randpass.py ExvoT8Hi
步驟二:改進腳本,生成指定位數的隨機密碼
上面程序的主要問題是,第一,生成的密碼倍數是固定的,若是但願生成其餘倍數的密碼,還須要從新改寫代碼;第二,若是生成密碼這個功能在其餘地方也須要使用,那麼代碼的重用性得不到體現。
改進的代碼能夠解以上兩個問題,具體以下:
[root@py01 bin]# vim randpass2.py #!/usr/bin/env python import string import random allchs = string.letters + string.digits def genPwd(num = 8): pwd = '' for i in range(num): pwd += random.choice(allchs) return pwd if __name__ == '__main__': print genPwd() print genPwd(6)
代碼執行結果以下:
[root@py01 bin]# ./randpass2.py hUEDcvmc RgNMhu [root@py01 bin]# ./randpass2.py s9Ojwpp7 70BOsU [root@py01 bin]# python Python 2.6.6 (r266:84292, Oct 12 2012, 14:23:48) [GCC 4.4.6 20120305 (Red Hat 4.4.6-4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import randpass2 >>> randpass2.genPwd(10) #在其餘位置也能夠直接調用randpass2模中的函數 'WobDgiHsC8'