1. 程式人生 > >《Python程式設計:從入門到實踐》第10章 筆記

《Python程式設計:從入門到實踐》第10章 筆記

備註:以下按照Python 2的規則編寫程式碼。
在jupyter notebook中執行直接顯示結果。

10 檔案和異常

10.1 檔案中讀取資料

"""10.1.1 讀取整個檔案"""
"""file_reader.py"""

with open('chapter_10/pi_digits.txt') as file_object:   # 關鍵字with在不再需要訪問檔案後將其關閉
    contents = file_object.read()
    print(contents)
3.1415926535
  8979323846
  2643383279
"""10.1.1 讀取整個檔案"""
"""file_reader.py""" with open('chapter_10/pi_digits.txt') as file_object: # 關鍵字with在不再需要訪問檔案後將其關閉 contents = file_object.read() print(contents.rstrip()) # 使用rstrip()刪除檔案末尾多餘的空行
3.1415926535
  8979323846
  2643383279
"""10.1.3 逐行讀取"""
"""file_reader.py"""

filename = 'chapter_10/pi_digits.txt'
with open(filename) as f: for line in f: print line with open(filename) as f: for line in f: print line.rstrip()
3.1415926535

  8979323846

  2643383279

3.1415926535
  8979323846
  2643383279
"""10.1.4 建立包含檔案各行內容的列表"""

filename = 'chapter_10/pi_digits.txt'

with open(filename) as
f: lines = f.readlines() print lines for line in lines: print line.rstrip()
['3.1415926535\n', '  8979323846\n', '  2643383279\n']
3.1415926535
  8979323846
  2643383279
"""10.1.5 使用檔案中的內容"""
"""pi_string.py"""

filename = 'chapter_10/pi_digits.txt'

with open(filename) as f:
    lines = f.readlines()


pi_string = ''
for line in lines:
    pi_string += line.rstrip()

print pi_string
print len(pi_string)
3.1415926535  8979323846  2643383279
36
"""10.1.5 使用檔案中的內容"""
"""pi_string.py"""

filename = 'chapter_10/pi_digits.txt'

with open(filename) as f:
    lines = f.readlines()


pi_string = ''
for line in lines:
    pi_string += line.strip()  # 刪除前後的空格

print pi_string
print len(pi_string)
3.141592653589793238462643383279
32

注意:

讀取文字檔案時,Python將其中的所有文字都解讀為字串。如果讀取的是數字,並要將其作為數值使用,就必須使用函式int()將其轉換為整數,或使用函式float()將其轉換為浮點數。

"""10.1.6  包含一百萬位的大型檔案 """
"""pi_string.py"""

filename = 'chapter_10/pi_million_digits.txt'

with open(filename) as f:
    lines = f.readlines()


pi_string = ''
for line in lines:
    pi_string += line.strip()

print pi_string[:52] + "..."    # 以列印小數點後50位為例
print len(pi_string)
3.14159265358979323846264338327950288419716939937510...
1000002
"""10.1.7  圓周率值中包含你的生日嗎 """

"""任務:確定某個生日是否包含在圓周率值的前1 000 000位中。"""


filename = 'chapter_10/pi_million_digits.txt'

with open(filename) as f:
    lines = f.readlines()


pi_string = ''
for line in lines:
    pi_string += line.rstrip()

birthday = raw_input("Enter your birthday, in the form mmddyy: ")
if birthday  in pi_string:
    print "Your birthday aperars in the first million digits of pi!"

else:
    print "Your birthday doesn't appear in the first million digits of pi."
Enter your birthday, in the form mmddyy: 120372
Your birthday aperars in the first million digits of pi!
"""10-1 Python學習筆記"""
"""
在文字編輯器中新建一個檔案,寫幾句話來總結一下你至此學到的 Python 知識,其中每一行都以“In Python you can”打頭。
將這檔案命名為learning_python.txt,並將其儲存到為完成本章練習而編寫的程式所在的目錄中。編寫一個程式,它讀取這個
檔案,並將你所寫的內容列印三次:第一次列印時讀取整個檔案;第二次列印時遍歷檔案物件;第三次列印時將各行儲存在一個列
表中,再在 with 程式碼塊外列印它們。
"""

with open('chapter_10/learning_python.txt') as lp:
    contents = lp.read()

print "1>>>" 
print contents


print "\n2>>>"
for line in contents:
    print line.strip()

print "\n3>>>"
with open('chapter_10/learning_python.txt') as lp:
    lines = lp.readlines()
    for line in lines:
        print line.rstrip()

1>>>
In Python you can do whatever you want!
In Python you can read different tpyes of files.
In Python you can draw something.
In Python you can program interesting games.

2>>>
I
n

P
y
t
h
o
n

y
o
u

c
a
n

d
o

w
h
a
t
e
v
e
r

y
o
u

w
a
n
t
!

I
n

P
y
t
h
o
n

y
o
u

c
a
n

r
e
a
d

d
i
f
f
e
r
e
n
t

t
p
y
e
s

o
f

f
i
l
e
s
.

I
n

P
y
t
h
o
n

y
o
u

c
a
n

d
r
a
w

s
o
m
e
t
h
i
n
g
.

I
n

P
y
t
h
o
n

y
o
u

c
a
n

p
r
o
g
r
a
m

i
n
t
e
r
e
s
t
i
n
g

g
a
m
e
s
.

3>>>
In Python you can do whatever you want!
In Python you can read different tpyes of files.
In Python you can draw something.
In Python you can program interesting games.
"""10-2 C語言學習筆記"""
"""
讀取你剛建立的檔案 learning_python.txt 中的每一行,使用方法replace()將其中的 Python 都替換為另一門語言的名稱,
如 C。將修改後的各行都列印到螢幕上。 
"""

message = "I really like dogs."
message.replace('dog', 'cat')

with open('chapter_10/learning_python.txt') as f:
    contents = f.read()

print contents
print "\nChange 'Python' to 'C'."
print contents.replace("Python", "C")   # replace()替換字串中特定單詞
In Python you can do whatever you want!
In Python you can read different tpyes of files.
In Python you can draw something.
In Python you can program interesting games.

Change 'Python' to 'C'.
In C you can do whatever you want!
In C you can read different tpyes of files.
In C you can draw something.
In C you can program interesting games.

10.2 寫入檔案

"""10.2.1 寫入空檔案"""
"""write_message.py"""

filename = 'chapter_10/programming1.txt'

with open(filename, 'w') as f:
    f.write("I love programming.")

# 驗證
with open(filename) as f:
    print "The following are in the file:"
    print f.read()
The following are in the file:
I love programming.

開啟檔案時,可指定讀取模式(’r’)、寫入模式(’w’)、附加模式(’a’)或讓你能夠讀取和寫入檔案的模式(’r+’)。如果省略了模式實參,Python將以預設的只讀模式開啟檔案。

如果要寫入的檔案不存在,函式open()將自動建立它。然而,以寫入(’w’)模式開啟檔案時千萬要小心,因為如果指定的檔案已經存在,Python將在返回檔案物件前清空該檔案。

注意:

Python只能將字串寫入文字檔案。要將數值資料儲存到文字檔案中,必須先使用函式str()將其轉換為字串格式。

"""10.2.2 寫入多行"""

filename = 'chapter_10/programming2.txt'

with open(filename, 'w') as f:
    f.write("I love programming.\n")   # 插入換行符,否則這兩句會連在一起
    f.write("I love creating new games.\n")   

# 驗證
with open(filename) as f:
    print "The following are in the file:"
    print f.read()
The following are in the file:
I love programming.
I love creating new games.
"""10.2.3 附加到檔案"""
"""
如果要給檔案新增內容,而不是覆蓋原有的內容,可以附加模式開啟檔案,寫入到檔案的行都將新增到檔案末尾。
如果指定的檔案不存在,Python將建立一個空檔案。
"""

filename = 'chapter_10/programming3.txt'

with open(filename, 'a') as f:
    f.write("I also love finding meaning in large dataset.\n")
    f.write("I love creating apps that can run in browser.\n")

# 驗證
with open(filename) as f:
    print "The following are in the file:"
    print f.read()
The following are in the file:
I love programming.
I love creating new games.
I also love finding meaning in large dataset.
I love creating apps that can run in browser.
"""10-3 訪客"""
"""
編寫一個程式,提示使用者輸入其名字;使用者作出響應後,將其名字寫入到檔案 guest.txt 中。 
"""

filename = "chapter_10/guest.txt"
name = raw_input("Hello!\nWhat's your name?\n")
with open(filename, "w") as f:
    f.write(name)

# 驗證
with open(filename) as f:
    print "The following are in the file:"
    print f.read()
Hello!
What's your name?
Dan
The following are in the file:
Dan
"""10-4 訪客名單"""
"""
編寫一個 while 迴圈,提示使用者輸入其名字。使用者輸入其名字後,在螢幕上列印一句問候語,並將一條訪問記錄新增到檔案 guest_book.txt 中。確保這個檔案中的每條記錄都獨佔一行。 
"""

filename = "chapter_10/guest_book.txt"
name = ""
with open(filename, "a") as f:
    while name != "quit":
        print "Enter 'quit' to quit this program."
        name = raw_input("Please write down your name: ")

        if name == "quit":
            break

        line =  "Hello! " + name + "\n"
        f.write(line)
        print line

Enter 'quit' to quit this program.
Please write down your name: Ann
Hello! Ann

Enter 'quit' to quit this program.
Please write down your name: Bob
Hello! Bob

Enter 'quit' to quit this program.
Please write down your name: Candy
Hello! Candy

Enter 'quit' to quit this program.
Please write down your name: Denny
Hello! Denny

Enter 'quit' to quit this program.
Please write down your name: quit

10.3 異常

"""10.3.1 ZeroDivisionError 異常"""
"""division.py"""

print 5/0
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-6-8c4a85b4b7dc> in <module>()
      2 """division.py"""
      3 
----> 4 print 5/0


ZeroDivisionError: integer division or modulo by zero

在上述traceback中,錯誤ZeroDivisionError是一個異常物件。Python無法按你的要求做時,就會建立這種物件。在這種情況下,Python將停止執行程式,並指出引發了哪種異常,而我們可根據這些資訊對程式進行修改。

下面我們將告訴Python,發生這種錯誤時怎麼辦;這樣,如果再次發生這樣的錯誤,我們就有備無患了。

"""10.3.2 使用try-except程式碼塊"""

"""處理ZeroDivisionError異常的try-except程式碼塊類似於下面這樣: """

try:
    print 5/0
except ZeroDivisionError:
    print "You can't divide by zero!"
You can't divide by zero!

在這個示例中,try程式碼塊中的程式碼引發了ZeroDivisionError異常,因此Python指出了該如何解決問題的except程式碼塊,並執行其中的程式碼。這樣,使用者看到的是一條友好的錯誤訊息,而不是traceback。

"""10.3.3  使用異常避免崩潰 """
"""
發生錯誤時,如果程式還有工作沒有完成,妥善地處理錯誤就尤其重要。這種情況經常會出現在要求使用者提供輸入的程式中;
如果程式能夠妥善地處理無效輸入,就能再提示使用者提供有效輸入,而不至於崩潰。 
下面來建立一個只執行除法運算的簡單計算器:
"""

"""division.py"""

print "Give me two numbers, and I'll divide them." 
print "Enter 'q' to quit."

while True: 
    first_number = raw_input("\nFirst number: ") 
    if first_number == 'q': 
        break 
    second_number = raw_input("Second number: ") 
    if second_number == 'q': 
        break 
    answer = float(first_number) / float(second_number) 
    print(answer) 
Give me two numbers, and I'll divide them.
Enter 'q' to quit.

First number: 5
Second number: 0



---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-11-32d5fd3de975> in <module>()
     17     if second_number == 'q':
     18         break
---> 19     answer = float(first_number) / float(second_number)
     20     print(answer)


ZeroDivisionError: float division by zero

程式崩潰可不好,但讓使用者看到traceback也不是好主意。不懂技術的使用者會被它們搞糊塗,而且如果使用者懷有惡意,他會通過traceback獲悉你不希望他知道的資訊。例如,他將知道你的程式檔案的名稱,還將看到部分不能正確執行的程式碼。有時候,訓練有素的攻擊者可根據這些資訊判斷出可對你的程式碼發起什麼樣的攻擊。

"""10.3.4  else 程式碼塊 """
"""
通過將可能引發錯誤的程式碼放在try-except程式碼塊中,可提高這個程式抵禦錯誤的能力。錯誤是執行除法運算的程式碼行導致的,
因此我們需要將它放到try-except程式碼塊中。這個示例還包含一個else程式碼塊;依賴於try程式碼塊成功執行的程式碼都應放到
else程式碼塊中: 
"""

print "Give me two numbers, and I'll divide them." 
print "Enter 'q' to quit."

while True: 
    first_number = raw_input("\nFirst number: ") 
    if first_number == 'q': 
        break 
    second_number = raw_input("Second number: ") 
    #if second_number == 'q': 
         #break
    try:
        answer = float(first_number) / float(second_number) 
    except ZeroDivisionError: 
        print "You can't divide by 0!"
    else:
        print(answer) 
Give me two numbers, and I'll divide them.
Enter 'q' to quit.

First number: 5
Second number: 0
You can't divide by 0!

First number: 5
Second number: 2
2.5

First number: q

try-except-else程式碼塊的工作原理大致如下:Python嘗試執行try程式碼塊中的程式碼;except程式碼塊告訴Python,如果它嘗試執行try程式碼塊中的程式碼時引發了指定的異常,該怎麼辦。

通過預測可能發生錯誤的程式碼,可編寫健壯的程式,它們即便面臨無效資料或缺少資源,也能繼續執行,從而能夠抵禦無意的使用者錯誤和惡意的攻擊。

"""10.3.5  處理 FileNotFoundError 異常 """
"""
使用檔案時,一種常見的問題是找不到檔案:你要查詢的檔案可能在其他地方、檔名可能不正確或者這個檔案根本就不存在。
對於所有這些情形,都可使用try-except程式碼塊以直觀的方式進行處理。 
我們來嘗試讀取一個不存在的檔案。下面的程式嘗試讀取檔案alice.txt的內容,但我沒有將這個檔案儲存在alice.py
所在的目錄中: 
"""

"""alice.py"""

filename = 'alice.txt' 

with open(filename) as f_obj: 
    contents = f_obj.read() 
---------------------------------------------------------------------------

IOError                                   Traceback (most recent call last)

<ipython-input-14-69c4fe15fe12> in <module>()
     10 filename = 'alice.txt'
     11 
---> 12 with open(filename) as f_obj:
     13     contents = f_obj.read()


IOError: [Errno 2] No such file or directory: 'alice.txt'

在這個示例中,這個錯誤是函式open()導致的,因此要處理這個錯誤,必須將try語句放在包含open()的程式碼行之前:

filename = 'alice.txt' 

try: 
    with open(filename) as f_obj: 
        contents = f_obj.read() 
except IOError: 
    msg = "Sorry, the file '" + filename + "' does not exist." 
    print msg
Sorry, the file 'alice.txt' does not exist.
"""10.3.6  分析文字 """
"""
下面來提取童話Alice  in  Wonderland的文字,並嘗試計算它包含多少個單詞。我們將使用方法split(),
它根據一個字串建立一個單詞列表。
"""

filename = 'chapter_10/alice.txt'

try:
    with open(filename) as f:
        contents = f.read()
except IOError:
    msg = "Sorry, the file '" + filename + "' does not exist."
    print msg
else:
    # 計算檔案大致包含多少個單詞
    words  = contents.split()
    num_words = len(words)
    print "The file '" + filename + "' has about " + str(num_words) + " words."
The file 'chapter_10/alice.txt' has about 29461 words.
"""10.3.7  使用多個檔案 """
"""
下面多分析幾本書。這樣做之前,我們先將這個程式的大部分程式碼移到一個名為count_words()的函式中,
這樣對多本書進行分析時將更容易: 
"""
"""word_count.py """

def count_words(filename): 
    """計算一個檔案大致包含多少個單詞""" 
    try: 
        with open(filename) as f_obj: 
            contents = f_obj.read()  
    except IOError: 
        msg = "Sorry, the file '" + filename + "' does not exist." 
        print(msg) 
    else: 
        # 計算檔案大致包含多少個單詞 
        words = contents.split() 
        num_words = len(words) 
        print "The file '" + filename + "' has about " + str(num_words) +  " words."

filenames = ['chapter_10/alice.txt', 'chapter_10/siddhartha.txt', 'chapter_10/moby_dick.txt', 'chapter_10/little_women.txt'] 
for filename in filenames: 
    count_words(filename) 
The file 'chapter_10/alice.txt' has about 29461 words.
Sorry, the file 'chapter_10/siddhartha.txt' does not exist.
The file 'chapter_10/moby_dick.txt' has about 215136 words.
The file 'chapter_10/little_women.txt' has about 189079 words.

檔案siddhartha.txt不存在,但這絲毫不影響這個程式處理其他檔案。
在這個示例中,使用try-except程式碼塊提供了兩個重要的優點:

  • 避免讓使用者看到traceback;
  • 讓程式能夠繼續分析能夠找到的其他檔案。

如果不捕獲因找不到siddhartha.txt而引發IOError異常,使用者將看到完整的traceback,而程式將在嘗試分析Siddhartha後停止執行——根本不分析Moby Dick和Little Women。

"""10.3.8  失敗時一聲不吭 """
"""
在前一個示例中,我們告訴使用者有一個檔案找不到。但並非每次捕獲到異常時都需要告訴使用者,有時候你希望程式在發生異常時
一聲不吭,就像什麼都沒有發生一樣繼續執行。要讓程式在失敗時一聲不吭,可像通常那樣編寫try程式碼塊,但在except程式碼塊
中明確地告訴Python什麼都不要做。Python有一個pass語句,可在程式碼塊中使用它來讓Python什麼都不要做: 
"""

def count_words(filename): 
    """計算一個檔案大致包含多少個單詞""" 
    try: 
        with open(filename) as f_obj: 
            contents = f_obj.read()  
    except IOError: 
         pass 
    else: 
        # 計算檔案大致包含多少個單詞 
        words = contents.split() 
        num_words = len(words) 
        print "The file '" + filename + "' has about " + str(num_words) +  " words."


filenames = ['chapter_10/alice.txt', 'chapter_10/siddhartha.txt', 'chapter_10/moby_dick.txt', 'chapter_10/little_women.txt'] 
for filename in filenames: 
    count_words(filename) 
The file 'chapter_10/alice.txt' has about 29461 words.
The file 'chapter_10/moby_dick.txt' has about 215136 words.
The file 'chapter_10/little_women.txt' has about 189079 words.

pass語句還充當了佔位符,它提醒你在程式的某個地方什麼都沒有做,並且以後也許要在這裡做些什麼。

例如,在這個程式中,我們可能決定將找不到的檔案的名稱寫入到檔案missing_files.txt中。使用者看不到這個檔案,但我們可以讀取這個檔案,進而處理所有檔案找不到的問題。

"""
10-6  加法運算:提示使用者提供數值輸入時,常出現的一個問題是,使用者提供的是文字而不是數字。在這種情況下,當你嘗試
將輸入轉換為整數時,將引發 TypeError 異常。編寫一個程式,提示使用者輸入兩個數字,再將它們相加並列印結果。在使用者
輸入的任何一個值不是數字時都捕獲 TypeError 異常,並列印一條友好的錯誤訊息。對你編寫的程式進行測試:先輸入兩個
數字,再輸入一些文字而不是數字。 
"""


print "Give me two numbers, and I'll add them."

num_1 = raw_input("First number: ")
num_2 = raw_input("Second number: ")

try:
    sum = float(num_1) + float(num_2)
except ValueError:
    print "\nYou didn't give me two NUMBERS!"
else:
    print "\nThe answer is: " + str(sum)


Give me two numbers, and I'll add them.
First number: 1.2
Second number: 4.3

The answer is: 5.5
"""
10-7  加法計算器:將你為完成練習 10-6 而編寫的程式碼放在一個 while 迴圈中,讓使用者犯錯(輸入的是文字而不是數字)
後能夠繼續輸入數字。 
"""


print "Give me two numbers, and I'll add them."
print "Enter 'q' to quit."


check = True
while check:
    num_1 = raw_input("\nFirst number: ")
    if num_1 == "q":
        break
    num_2 = raw_input("Second number: ")
    if num_2 == "q":
        break
    try:
        sum = float(num_1) + float(num_2)
    except ValueError:
        print "\nYou didn't give me two NUMBERS!"
        continue
    else:
        print "\nThe answer is: " + str(sum)
        check = False

Give me two numbers, and I'll add them.
Enter 'q' to quit.

First number: d
Second number: g

You didn't give me two NUMBERS!

First number: 3
Second number: o

You didn't give me two NUMBERS!

First number: 7
Second number: 6

The answer is: 13.0
"""
10-8 貓和狗:
建立兩個檔案 cats.txt 和 dogs.txt,在第一個檔案中至少儲存三隻貓的名字,在第二個檔案中至少儲存三條狗的名字。
編寫一個程式,嘗試讀取這些檔案,並將其內容列印到螢幕上。將這些程式碼放在一個 try-except 程式碼塊中,以便在檔案不
存在時捕獲 FileNotFound 錯誤,並列印一條友好的訊息。將其中一個檔案移到另一個地方,並確認 except 程式碼塊中的
程式碼將正確地執行。 
"""
catsname = "chapter_10/cats.txt"
dogsname = "chapter_10/dogs.txt"

def readfile(filename):

        try:
            with open(filename) as f:
                print filename.upper()
                print f.read()
        except IOError:
            print "The '" + filename + "' does not exist!"


readfile(catsname)   
readfile(dogsname)   
The 'chapter_10/cats.txt' does not exist!
The 'chapter_10/dogs.txt' does not exist!
"""
10-9 沉默的貓和狗:修改你在練習 10-8 中編寫的 except 程式碼塊,讓程式在檔案不存在時一言不發。 
"""
catsname = "chapter_10/cats.txt"
dogsname = "chapter_10/dogs.txt"

def readfile(filename):

        try:
            with open(filename) as f:
                print filename.upper()
                print f.read()
        except IOError:
            pass

        print "Complete."   

readfile(catsname)   
readfile(dogsname)   
Complete.
Complete.

10.4 儲存資料

模組json讓你能夠將簡單的Python資料結構轉儲到檔案中,並在程式再次執行時載入該檔案中的資料。你還可以使用json在Python程式之間分享資料。

更重要的是,JSON資料格式並非Python專用的,這讓你能夠將以JSON格式儲存的資料與使用其他程式語言的人分享。這是一種輕便格式,很有用,也易於學習。

10.4.1 使用 json.dump()和 json.load()

函式json.dump()接受兩個實參:要儲存的資料以及可用於儲存資料的檔案物件。


"""number_write.py"""

import json  # 匯入json模組

numbers = [2, 3, 5, 7, 11, 13]

filename = 'chapter_10/numbers.json'
with open(filename, 'w') as f:
    json.dump(numbers, f)
"""number_reader.py"""

filename = 'chapter_10/numbers.json'
with open(filename) as f:
    numbers = json.load(f)

print numbers    
[2, 3, 5, 7, 11, 13]

10.4.2 儲存和讀取使用者生成的資料

"""儲存使用者的名字"""
"""remember_me.py"""

import json

username = raw_input("What's your name? ")

filename = "chapter_10/username.json"
with open(filename, "w") as f:
    json.dump(username, f)
    print "We'll remember you when you come back, " + username + "!"
What's your name? Eric
We'll remember you when you come back, Eric!
"""再編寫一個程式,向其名字被儲存的使用者發出問候: """
"""greet_user.py """

import json
filename = "chapter_10/username.json"

with open(filename) as f:
    username = json.load(f)
    print "Welcome back, " + username + "!"
Welcome back, Eric!
"""合併兩個檔案"""
"""remember_me.py"""

import json

# 如果以前儲存了使用者名稱,就載入它
# 否則,就提示使用者輸入使用者名稱並存儲它

filename = "chapter_10/username.json"

try:
    with open(filename) as f:
        username = json.load(f)

except IOError:
    username = raw_input("What's  your name? ")
    with open(filename, "w") as f:
        json.dump(username, f)
        print "We'll remember you when you come back, " + username + "!"
else:
    print "Welcome back, " + username + "!"
Welcome back, Eric!
"""
10.4.3  重構 
你經常會遇到這樣的情況:程式碼能夠正確地執行,但可做進一步的改進——將程式碼劃分為一系列完成具體工作的函式。這樣的過程
被稱為重構。重構讓程式碼更清晰、更易於理解、更容易擴充套件。 
要重構remember_me.py,可將其大部分邏輯放到一個或多個函式中。remember_me.py的重點是問候使用者,因此我們將其所
有程式碼都放到一個名為greet_user()的函式中: 
"""
"""remrember_me.py"""

def greet_user():
    """問候使用者,並指出其名字"""
    filename = "chapter_10/username.json"
    try:
        with open(filename) as f:
            username = json.load(f)  
    except IOError:
        username = raw_input("What's  your name? ")
        with open(filename, "w") as f:
            json.dump(username, f)
            print "We'll remember you when you come back, " + username + "!"
    else:
        print "Welcome back, " + username + "!"


greet_user()        
Welcome back, Eric!
"""
下面來重構greet_user(),讓它不執行這麼多工。為此,我們首先將獲取儲存的使用者名稱的程式碼移到另一個函式中: 
"""

import json

def get_stored_username():
     """如果儲存了使用者名稱,就獲取它""" 
    filename = "chapter_10/username.json"
    try:
        with open(filename) as f:
            username = json.load(f)  
    except IOError:
        return None
    else:
        return username

def greet_user():
    username = get_stored_username()
    if username:
        print "Welcome back, " + username + "!"
    else:
        username = raw_input("What's  your name? ")
        with open(filename, "w") as f:
            json.dump(username, f)
            print "We'll remember you when you come back, " + username + "!"

greet_user()    
Welcome back, Eric!
"""
我們還需將greet_user()中的另一個程式碼塊提取出來:將沒有儲存使用者名稱時提示使用者輸入的程式碼放在一個獨立的函式中: 
"""

import json



def get_stored_username():

    try:
        with open(filename) as f:
            username = json.load(f)  
    except IOError:
        return None
    else:
        return username

def get_new_username(): 
    """提示使用者輸入使用者名稱""" 
    username = raw_input("What is your name? ") 
    filename = "chapter_10/username.json"
    with open(filename, 'w') as f: 
        json.dump(username, f) 
    return username 

def greet_user(): 

    username = get_stored_username() 
    if username: 
        print "Welcome back, " + username + "!"
    else: 
        username = get_new_username()   
        print "We'll remember you when you come back, " + username + "!" 


greet_user() 
Welcome back, Eric!

在remember_me.py的這個最終版本中,每個函式都執行單一而清晰的任務。

我們呼叫greet_user(),它列印一條合適的訊息:要麼歡迎老使用者回來,要麼問候新使用者。

為此,它首先呼叫get_stored_username(),這個函式只負責獲取儲存的使用者名稱(如果儲存了的話),再在必要時呼叫get_new_username(),這個函式只負責獲取並存儲新使用者的使用者名稱。要編寫出清晰而易於維護和擴充套件的程式碼,這種劃分工作必不可少。

"""
10-11  喜歡的數字:編寫一個程式,提示使用者輸入他喜歡的數字,並使用json.dump()將這個數字儲存到檔案中。
再編寫一個程式,從檔案中讀取這個值,並列印訊息“I know your favorite number! It’s _____.”。 
"""

import json

filename = "chapter_10/favorite_number.json"
num = raw_input("What's your favorite number? ")
with open(filename, "w") as f:
    json.dump(num, f)


with open(filename) as f:
    answer = json.load(f)

print "I know your favorite number! It's " + str(answer) + "."  
What's your favorite number? 20
I know your favorite number! It's 20.
"""
10-12  記住喜歡的數字:將練習 10-11 中的兩個程式合而為一。如果儲存了使用者喜歡的數字,就向用戶顯示它,
否則提示使用者輸入他喜歡的數字並將其儲存到檔案中。執行這個程式兩次,看看它是否像預期的那樣工作。 
"""

import json

filename = "chapter_10/favorite_number.json"

with open(filename) as f:

    try:
        answer = json.load(f)   
        print "I know your favorite number! It's " + str(answer) + "." 
    except ValueError:
        print "Oh, I don't know your favorite number."
        num = raw_input("So what's your favorite number? ")
        with open(filename, "w") as f:
            json.dump(num, f)


I know your favorite number! It's 20.
"""
10-13 驗證使用者:最後一個 remember_me.py 版本假設使用者要麼已輸入其使用者名稱,要麼是首次執行該程式。我們應修改
這個程式,以應對這樣的情形:當前和最後一次執行該程式的使用者並非同一個人。 
為此,在 greet_user()中列印歡迎使用者回來的訊息前,先詢問他使用者名稱是否是對的。
如果不對,就呼叫 get_new_username()讓使用者輸入正確的使用者名稱。
"""

import json

def get_stored_username(): 
    filename = "chapter_10/username.json"
    try:
        with open(filename) as f:
            username = json.load(f)  
    except IOError:
        return None
    else:
        return username

def get_new_username(): 
    """提示使用者輸入使用者名稱""" 
    username = raw_input("What is your name ? ") 
    filename = "chapter_10/username.json"
    with open(filename, 'w') as f: 
        json.dump(username, f) 
    return username 

def greet_user():     
    username = get_stored_username() 
    if username: 
        check = raw_input("Are you " + username + " ? y/s ")
        if check == "y":
            print "Welcome back, " + username + "!"
        if check == "n":
            print "I's sorry."
            username = get_new_username()
            print "We'll remember you when you come back, " + username + "!" 
    else: 
        username = get_new_username()   
        print "We'll remember you when you come back, " + username + "!" 


greet_user() 
Are you Ada ? y/s n
I'm sorry.
What is your name ? Eric
We'll remember you when you come back, Eric!