斐波那契數列

案例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'
相關文章
相關標籤/搜索