《Python程式設計:從入門到實踐》 筆記(一)基礎知識

SJLin96發表於2018-08-20

 

目錄

第02章 變數和簡單資料型別

第03章 列表簡介

第04章 操作列表

第05章 if語句

第06章 字典

第07章 使用者輸入和while迴圈

第08章 函式

第09章 類

第10章 檔案和異常

第11章 測試程式碼


  • 如果你只求很簡單的應用、如果你學過其他語言,那麼看這一篇就已經可以做到使用Python 程式設計了。

 

第02章 變數和簡單資料型別

1. 變數

  • 變數:我們新增了一個名為message 的變數 。每個變數都儲存了一個值 :與變數相關聯的資訊。
    在程式中可隨時修改變數的值,而Python將始終記錄變數的最新值。
message = "Hello Python world!"
print(message)
message = "Hello Python Crash Course world!"
print(message)
  • 變數的命名和使用:

    ①變數名只能包含字母(最好用小寫字母)、數字和下劃線。變數名可以字母或下劃線打頭,但不能以數字打頭,例如,可將變數命名為message_1,但不能將其命名為1_message。

    ②變數名不能包含空格,但可使用下劃線來分隔其中的單詞。例如,變數名greeting_message可行,但變數名greeting message會引發錯誤。

    ③不要將Python關鍵字和函式名用作變數名,即不要使用Python保留用於特殊用途的單詞,如print。

    ④變數名應既簡短又具有描述性。例如,name比n好,student_name比s_n好,name_length比length_of_persons_name好。

    ⑤慎用小寫字母l和大寫字母O,因為它們可能被人錯看成數字1和0。

 

2. 字串

  • 字串:就是一系列字元。在Python中,用引號括起的都是字串,其中的引號可以是單引號,也可以是雙引號。這種靈活性讓你能夠在字串中包含引號和撇號:
'I told my friend, "Python is my favorite language!"'
"The language 'Python' is named after Monty Python, not the snake."
"One of Python's strengths is its diverse and supportive community."
  • 使用方法修改字串的大小寫:
name = "ada lovelace"
print(name.title())

#輸出:Ada Lovelace
  • 方法title() 出現在這個變數的後面。方法 是Python可對資料執行的操作。
    在name.title() 中,name 後面的句點(. )讓Python對變數name 執行方法title() 指定的操作。每個方法後面都跟著一對括號,這是因為方法通常需要額外的資訊來完成其工作。這種資訊是在括號內提供的。函式title() 不需要額外的資訊,因此它後面的括號是空的。
name = "Ada Lovelace"
print(name.upper())
print(name.lower())

#輸出:ADA LOVELACE
#     ada lovelace

 

  • 合併(拼接)字串:
    Python使用加號(+ )來合併字串。在這個示例中,我們使用+ 來合併first_name 、空格和last_name ,以得到完整的姓名,其結果如下:
first_name = "ada"
last_name = "lovelace"
full_name = first_name + " " + last_name
print(full_name)


#輸出:ada lovelace
first_name = "ada"
last_name = "lovelace"
full_name = first_name + " " + last_name
print("Hello, " + full_name.title() + "!")

#輸出:Hello, Ada Lovelace!

 

  • python字串中,同樣可以用\t 和 \n等製表符。
  • 刪除字串末尾多餘的空白:
    ① >>> favorite_language = 'python '
    ② >>> favorite_language
    'python '
    ③ >>> favorite_language.rstrip()
    'python'
    ④ >>> favorite_language
    'python '
    儲存在變數favorite_language 中的字串末尾包含多餘的空白(見①)。你在終端會話中向Python詢問這個變數的值時,可看到末尾的空格(見②)。對變
    量favorite_language 呼叫方法rstrip() 後(見③),這個多餘的空格被刪除了。然而,這種刪除只是暫時的,接下來再次詢問favorite_language 的值時,你會發
    現這個字串與輸入時一樣,依然包含多餘的空白(見④)。
    要永久刪除這個字串中的空白,必須將刪除操作的結果存回到變數中:
    favorite_language = 'python '
    favorite_language = favorite_language.rstrip()
  • 你還可以剔除字串開頭的空白:可使用方法 lstrip()

 

3. 數字

①整數

  • 在Python中,可對整數執行加(+ )減(- )乘(* )除(/ )求模(%)運算:

>>> 2 + 3
5 >>> 3
-
2
1 >>> 2
*
3
6 >>> 3
/
2
1.5
  • Python使用兩個乘號表示乘方運算
>>> 3 ** 2
9 
>>> 3 ** 3
27
>>> 10 ** 6
1000000
  • Python還支援運算次序,因此你可在同一個表示式中使用多種運算。你還可以使用括號來修改運算次序,讓Python按你指定的次序執行運算,如下所示:
>>> 2 + 3*4
14
>>> (2 + 3) * 4
20
  • 空格不影響Python計算表示式的方式,它們的存在旨在讓你閱讀程式碼時,能迅速確定先執行哪些運算。

②浮點數

  • 從很大程度上說,使用浮點數時都無需考慮其行為。你只需輸入要使用的數字,Python通常都會按你期望的方式處理它們。但需要注意的是,結果包含的小數位數可能是不確定的:
>>> 0.2 + 0.1
0.30000000000000004
>>> 3 * 0.1
0.30000000000000004
  • 錯誤的程式碼,因為:Python發現你使用了一個值為整數(int )的變數,但它不知道該如何解讀這個值。Python知道,這個變數表示的可能是數值23,也可能是字元2和3。像上面這樣在字串中使用整數時,需要顯式地指出你希望Python將這個整數用作字串。
     
    age = 23
    message = "Happy " + age + "rd Birthday!"
    print(message)
    為此,可呼叫函式str() ,它讓Python將非字串值表示為字串
    age = 23
    message = "Happy " + str(age) + "rd Birthday!"
    print(message)

     

4.註釋

  • 在Python中,註釋用井號(# )標識。井號後面的內容都會被Python直譯器忽略。

 

第03章 列表簡介

1. 列表

  • 列表讓你能夠在一個地方儲存成組的資訊,其中可以只包含幾個元素,也可以包含數百萬個元素。列表是新手可直接使用的最強大的Python功能之一,它融合了眾多重要的程式設計概念。
  • 列表:由一系列按特定順序排列的元素組成。你可以建立包含字母表中所有字母、數字0~9或所有家庭成員姓名的列表;也可以將任何東西加入列表中,其中的元素之間可以沒有任何關係。

 

  • 在Python中,用方括號([] )來表示列表,並用逗號來分隔其中的元素:
bicycles = ['trek', 'cannondale', 'redline', 'specialized']
print(bicycles)

#輸出:
#['trek', 'cannondale', 'redline', 'specialized']
  • 訪問列表元素,下面的程式碼從列表bicycles 中提取第一款自行車(你還可以對任何列表元素呼叫第2章介紹的字串方法):
bicycles = ['trek', 'cannondale', 'redline', 'specialized']
print(bicycles[0])

#輸出:trek
  • Python為訪問最後一個列表元素提供了一種特殊語法。通過將索引指定為-1 ,可讓Python返回最後一個列表元素:
bicycles = ['trek', 'cannondale', 'redline', 'specialized']
print(bicycles[-1])

#輸出:specialized

2. 修改、新增和刪除元素

  • 修改元素
motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles)
motorcycles[0] = 'ducati'
print(motorcycles)
  • 給列表附加元素時,它將新增到列表末尾。繼續使用前一個示例中的列表,在其末尾新增新元素'ducati' :
motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles)
motorcycles.append('ducati')
print(motorcycles)

#輸出:
#['honda', 'yamaha', 'suzuki']
#['honda', 'yamaha', 'suzuki', 'ducati']
  • 你可以先建立一個空列表,再使用一系列的append() 語句新增元素。
motorcycles = []
motorcycles.append('honda')
motorcycles.append('yamaha')
motorcycles.append('suzuki')
print(motorcycles)
  • 使用方法insert() 可在列表的任何位置新增新元素。這種操作將插入位置及其後面的每個元素都右移一個位置:
motorcycles = ['honda', 'yamaha', 'suzuki']
motorcycles.insert(0, 'ducati')
print(motorcycles)
  • 如果知道要刪除的元素在列表中的位置,可使用del 語句:
motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles)
del motorcycles[1]
print(motorcycles)
  • 方法pop() 可刪除列表末尾的元素,並讓你能夠接著使用它:
motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles)
popped_motorcycle = motorcycles.pop()
print(motorcycles)
print(popped_motorcycle)


#輸出:
#['honda', 'yamaha', 'suzuki']
#['honda', 'yamaha']
#suzuki
  • 實際上,你可以使用pop() 來刪除列表中任何位置的元素,只需在括號中指定要刪除的元素的索引即可:
motorcycles = ['honda', 'yamaha', 'suzuki']
first_owned = motorcycles.pop(0)
print('The first motorcycle I owned was a ' + first_owned.title() + '.')
  • 有時候,你不知道要從列表中刪除的值所處的位置。如果你只知道要刪除的元素的值,可使用方法remove() :
motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati']
print(motorcycles)

too_expensive = 'ducati'
motorcycles.remove(too_expensive)

print(motorcycles)
print("\nA " + too_expensive.title() + " is too expensive for me.")

3. 組織列表

  • Python方法sort() 讓你能夠較為輕鬆地對列表進行排序:
cars = ['bmw', 'audi', 'toyota', 'subaru']
cars.sort()
print(cars)


#輸出:
#['audi', 'bmw', 'subaru', 'toyota']
  • 你還可以按與字母順序相反的順序排列列表元素,為此,只需向sort() 方法傳遞引數reverse=True:
cars = ['bmw', 'audi', 'toyota', 'subaru']
cars.sort(reverse=True)
print(cars)
  • 要保留列表元素原來的排列順序,同時以特定的順序呈現它們,可使用函式sorted() 。函式sorted() 讓你能夠按特定順序顯示列表元素,同時不影響它們在列表中的原始排列順序:
cars = ['bmw', 'audi', 'toyota', 'subaru']
print("Here is the original list:")
print(cars)

print("\nHere is the sorted list:")
print(sorted(cars))

print("\nHere is the original list again:")
print(cars)
  • 要反轉列表元素的排列順序,可使用方法reverse() :
cars = ['bmw', 'audi', 'toyota', 'subaru']
print(cars)
cars.reverse()
print(cars)
  • 使用函式len() 可快速獲悉列表的長度:
cars = ['bmw', 'audi', 'toyota', 'subaru']
print(len(cars))

 

第04章 操作列表

1. 遍歷整個列表

  • for迴圈遍歷:
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(magician)
  • 在for 迴圈中,想包含多少行程式碼都可以。在程式碼行for magician in magicians 後面,每個縮排的程式碼行都是迴圈的一部分,且將針對列表中的每個值都執行一次。因此,可對列表中的每個值執行任意次數的操作:
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(magician.title() + ", that was a great trick!")
    print("I can't wait to see your next trick, " + magician.title() + ".\n")
  • for 語句末尾的冒號告訴Python,下一行是迴圈的第一行。如果你不小心遺漏了冒號,將導致語法錯誤,因為Python不知道你意欲何為。

2.建立數值列表

  • Python函式range() 讓你能夠輕鬆地生成一系列的數字。range() 只是列印數字1~4,這是你在程式語言中經常看到的差一行為的結果。函式range() 讓Python從你指定的第一個值開始數,並在到達你指定的第二個值後停止,因此輸出不包含第二個值(這裡為5):
for value in range(1,5):
    print(value)


#輸出:
#1
#2
#3
#4
  • 要建立數字列表,可使用函式list() 將range() 的結果直接轉換為列表。如果將range() 作為list() 的引數,輸出將為一個數字列表:
numbers = list(range(1,6))
print(numbers)
  • 使用函式range() 時,還可指定步長。例如,下面的程式碼列印1~10內的偶數:
even_numbers = list(range(2,11,2))
print(even_numbers)
  • 使用函式range() 幾乎能夠建立任何需要的數字集,例如,如何建立一個列表,其中包含前10個整數(即1~10)的平方呢?在Python中,兩個星號(** )表示乘方運算。下面的程式碼演示瞭如何將前10個整數的平方加入到一個列表中:
squares = []
for value in range(1,11):
    square = value**2
    squares.append(square)
print(squares)
  • 有幾個專門用於處理數字列表的Python函式。例如,你可以輕鬆地找出數字列表的最大值、最小值和總和:
digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
print(min(digits))
print(max(digits))
print(sum(digits))

 

  • 列表解析:將for 迴圈和建立新元素的程式碼合併成一行,並自動附加新元素。
  • 要使用這種語法,首先指定一個描述性的列表名,如squares ;然後,指定一個左方括號,並定義一個表示式,用於生成你要儲存到列表中的值。
    在這個示例中,表示式為value**2 ,它計算平方值。接下來,編寫一個for 迴圈,用於給表示式提供值,再加上右方括號。在這個示例中,for 迴圈為for value in range(1,11) ,它將值1~10提供給表示式value**2 。請注意,這裡的for 語句末尾沒有冒號。
squares = [value**2 for value in range(1,11)]
print(squares)

3. 使用列表的一部分

  • 你可以處理列表的部分元素——Python稱之為切片
  • 要建立切片,可指定要使用的第一個元素和最後一個元素的索引。與函式range() 一樣,Python在到達你指定的第二個索引前面的元素後停止。要輸出列表中的前三個元素,需要指定索引0~3,這將輸出分別為0 、1 和2 的元素:
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[0:3])

#輸出:['charles', 'martina', 'michael']
  • 如果你沒有指定第一個索引,Python將自動從列表開頭開始。要讓切片終止於列表末尾,也可使用類似的語法。
#自動從頭開始
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[:4])

#自動到尾部結束
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[2:])
  • 負數索引返回離列表末尾相應距離的元素,因此你可以輸出列表末尾的任何切片。
    例如,如果你要輸出名單上的最後三名隊員,可使用切片players[-3:] :
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[-3:])

 

  • 如果要遍歷列表的部分元素,可在for 迴圈中使用切片:
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print("Here are the first three players on my team:")
for player in players[:3]:
    print(player.title())
  • 通過切片複製一個列表(會有兩個列表):
my_foods = ['pizza', 'falafel', 'carrot cake']

#會有兩個不同的列表存在
friend_foods = my_foods[:]
my_foods.append('cannoli')
friend_foods.append('ice cream')
  • 而下面這個例子將my_foods 賦給friend_foods ,而不是將my_foods 的副本儲存到friend_foods 。這種語法實際上是讓Python將新變數friend_foods 關聯到包含在my_foods 中的列表,因此這兩個變數都指向同一個列表
my_foods = ['pizza', 'falafel', 'carrot cake']

#這行不通
friend_foods = my_foods
my_foods.append('cannoli')
friend_foods.append('ice cream')

4.元組

  • 有時候你需要建立一系列不可修改的元素,元組可以滿足這種需求。Python將不能修改的值稱為不可變的 ,而不可變的列表被稱為元組
  • 元組看起來猶如列表,但使用圓括號而不是方括號來標識。定義元組後,就可以使用索引來訪問其元素,就像訪問列表元素一樣。
dimensions = (200, 50)
print(dimensions[0])
print(dimensions[1])
  • 像列表一樣,也可以使用for 迴圈來遍歷元組中的所有值。
  • 雖然不能修改元組的元素,但可以給儲存元組的變數賦值。因此,如果要修改前述矩形的尺寸,可重新定義整個元組:
dimensions = (200, 50)
print("Original dimensions:")
for dimension in dimensions:
    print(dimension)

dimensions = (400, 100)
print("\nModified dimensions:")
for dimension in dimensions:
    print(dimension)

5. 程式碼格式

  • Python改進提案 (Python Enhancement Proposal,PEP):PEP 8是最古老的PEP之一,它向Python程式設計師提供了程式碼格式設定指南。PEP 8的篇幅很長,但大都與複雜的編碼結構相關。

 

  • PEP 8建議每級縮排都使用四個空格,這既可提高可讀性,又留下了足夠的多級縮排空間。
  • 你在編寫程式碼時應該使用製表符鍵,但一定要對編輯器進行設定,使其在文件中插入空格而不是製表符。在程式中混合使用製表符和空格可能導致極難解決的問題。

 

  • 很多Python程式設計師都建議每行不超過80字元。
  • PEP 8還建議註釋的行長都不超過72字元,因為有些工具為大型專案自動生成文件時,會在每行註釋開頭新增格式化字元。

 

第05章 if語句

1. 條件測試

  • 這個示例中的迴圈首先檢查當前的汽車名是否是'bmw' 。如果是,就以全大寫的方式列印它;否則就以首字母大寫的方式列印:
cars = ['audi', 'bmw', 'subaru', 'toyota']
for car in cars:
    if car == 'bmw':
        print(car.upper())
    else:
        print(car.title())
  • 在Python中檢查是否相等時區分大小寫,例如,兩個大小寫不同的值會被視為不相等:
car = 'Audi'
car == 'audi' #False
  • 如果大小寫無關緊要,而只想檢查變數的值,可將變數的值轉換為小寫,再進行比較:
car = 'Audi'
car.lower() == 'audi'    #True
  • 要判斷兩個值是否不等,可結合使用驚歎號和等號(!= ),其中的驚歎號表示不 ,在很多程式語言中都如此。
  • python中可以使用==、<、>、<=、>=來進行數值比較。
  • PEP 8提供的建議是,在諸如== 、>= 和<= 等比較運算子兩邊各新增一個空格。

 

  • 可以用and和or來檢查多個條件:
age_0 = 22
age_1 = 18
age_0 >= 21 and age_1 >= 21 #False
age_0 = 22
age_1 = 18
age_0 >= 21 or age_1 >= 21 #True

 

  • 還有些時候,確定特定的值未包含在列表中很重要;在這種情況下,可使用關鍵字not in 。例如,如果有一個列表,其中包含被禁止在論壇上發表評論的使用者,就可在允許使用者提交評論前檢查他是否被禁言:
banned_users = ['andrew', 'carolina', 'david']
user = 'marie'
if user not in banned_users:
    print(user.title() + ", you can post a response if you wish.")
  • 布林表示式
game_active = True
can_edit = False

2. if語句

  • 最簡單的if 語句只有一個測試和一個操作。在緊跟在if 語句後面的程式碼塊中,可根據需要包含任意數量的程式碼行。
if conditional_test:
    do something
  • 經常需要在條件測試通過了時執行一個操作,並在沒有通過時執行另一個操作;在這種情況下,可使用Python提供的if-else 語句。
age = 17

if age >= 18:
    print("You are old enough to vote!")
    print("Have you registered to vote yet?")
else:
    print("Sorry, you are too young to vote.")
    print("Please register to vote as soon as you turn 18!")
  • 經常需要檢查超過兩個的情形,為此可使用Python提供的if-elif-else 結構。Python只執行if-elif-else 結構中的一個程式碼塊。
age = 12

if age < 4:
    print("Your admission cost is $0.")
elif age < 18:
    print("Your admission cost is $5.")
else:
    print("Your admission cost is $10.")

 

  • 可根據需要使用任意數量的elif 程式碼塊。
  • Python並不要求if-elif 結構後面必須有else 程式碼塊。

 

3. 使用if語句處理列表

  • 通過結合使用if 語句和列表,可完成一些有趣的任務:對列表中特定的值做特殊處理;高效地管理不斷變化的情形,如餐館是否還有特定的食材;證明程式碼在各種情形下都將按預期那樣執行。

 

  • 比薩店在製作比薩時,每新增一種配料都列印一條訊息。通過建立一個列表,在其中包含顧客點的配料,並使用一個迴圈來指出新增到比薩中的配料。然而,如果比薩店的青椒用完了,該如何處理呢?為妥善地處理這種情況,可在for 迴圈中包含一條if 語句:
requested_toppings = ['mushrooms', 'green peppers', 'extra cheese']

for requested_topping in requested_toppings:
    if requested_topping == 'green peppers':
        print("Sorry, we are out of green peppers right now.")
    else:
        print("Adding " + requested_topping + ".")

print("\nFinished making your pizza!")

 

  • 預先確定列表不是空的
requested_toppings = []
if requested_toppings:
    for requested_topping in requested_toppings:
        print("Adding " + requested_topping + ".")
    print("\nFinished making your pizza!")
else:
    print("Are you sure you want a plain pizza?")
  • 使用多個列表
available_toppings = ['mushrooms', 'olives', 'green peppers',
                      'pepperoni', 'pineapple', 'extra cheese']
requested_toppings = ['mushrooms', 'french fries', 'extra cheese']

for requested_topping in requested_toppings:
    if requested_topping in available_toppings:
        print("Adding " + requested_topping + ".")
    else:
        print("Sorry, we don't have " + requested_topping + ".")
print("\nFinished making your pizza!")

 

第06章 字典

1. 使用字典

  • 在Python中,字典:是一系列 鍵 - 值對 。每個鍵都與一個值相關聯,你可以使用鍵來訪問與之相關聯的值。
  • 鍵 - 值對:兩個相關聯的值。指定鍵時,Python將返回與之相關聯的值。
  • 值:可以是數字、字串、列表乃至字典。事實上,可將任何Python物件用作字典中的值。
  • 在Python中,字典用放在花括號{} 中的一系列 鍵 - 值對 表示。鍵和值之間用冒號分隔,而鍵 - 值對之間用逗號分隔。
  • 在字典中,你想儲存多少個鍵—值對都可以。最簡單的字典只有一個鍵—值對

 

  • 要獲取與鍵相關聯的值,可依次指定字典名和放在方括號內的鍵。
alien_0 = {'color': 'green', 'points': 5}
print(alien_0['color'])
print(alien_0['points'])

#輸出:
#green
#5
  • 要新增鍵—值對,可依次指定字典名、用方括號括起的鍵和相關聯的值。
alien_0 = {'color': 'green', 'points': 5}

print(alien_0)
alien_0['x_position'] = 0
alien_0['y_position'] = 25
print(alien_0)


#輸出:
#{'color': 'green', 'points': 5}
#{'color': 'green', 'points': 5, 'y_position': 25, 'x_position': 0}
  • 要修改字典中的值,可依次指定字典名、用方括號括起的鍵以及與該鍵相關聯的新值。
alien_0 = {'color': 'green'}

alien_0['color'] = 'yellow'
  • 對於字典中不再需要的資訊,可使用del 語句將相應的鍵-值對徹底刪除。使用del 語句時,必須指定字典名和要刪除的鍵。刪除的鍵-值對永遠消失了
alien_0 = {'color': 'green', 'points': 5}

del alien_0['points']

 

  • 你也可以使用字典來儲存眾多物件的同一種資訊。我們將一個較大的字典放在了多行中。
  • 確定需要使用多行來定義字典時,在輸入左花括號後按Enter鍵,再在下一行縮排四個空格,指定第一個鍵-值對,並在它後面加上一個逗號。此後你再次按Enter鍵時,文字編輯器將自動縮排後續鍵-值對,且縮排量與第一個鍵-值對相同。
  • 定義好字典後,在最後一個鍵-值對的下一行新增一個右花括號,並縮排四個空格,使其與字典中的鍵對齊。另外一種不錯的做法是在最後一個鍵-值對後面也加上逗號,為以後在下一行新增鍵-值對做好準備。
favorite_languages = {
    'jen': 'python',
    'sarah': 'c',
    'edward': 'ruby',
    'phil': 'python',
    }

2. 遍歷字典

  • 字典可用於以各種方式儲存資訊,因此有多種遍歷字典的方式:可遍歷字典的所有鍵—值對、鍵或值。
  • 要編寫用於遍歷字典的for 迴圈,可宣告兩個變數,用於儲存鍵—值對中的鍵和值。對於這兩個變數,可使用任何名稱。for 語句的第二部分包含字典名和方法items() ,它返回一個鍵—值對列表。
user_0 = {
'username': 'efermi',
'first': 'enrico',
'last': 'fermi',
}

for key, value in user_0.items():
    print("\nKey: " + key)
    print("Value: " + value)
  • 即便遍歷字典時,鍵-值對 的返回順序也與儲存順序不同。Python不關心鍵—值對的儲存順序,而只跟蹤鍵和值之間的關聯關係。

 

  • 遍歷字典中的所有鍵:在不需要使用字典中的值時,方法keys() 很有用。
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
for name in favorite_languages.keys():
    print(name.title())
  • 遍歷字典時,會預設遍歷所有的鍵,因此,如果將上述程式碼中的for name in favorite_languages.keys(): 替換為for name in favorite_languages: ,輸出將不變。
  • 按順序遍歷字典中的所有鍵,可使用函式sorted() 來獲得按特定順序排列的鍵列表的副本:
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
for name in sorted(favorite_languages.keys()):
    print(name.title() + ", thank you for taking the poll.")

 

  • 遍歷字典中的所有值:如果你感興趣的主要是字典包含的值,可使用方法values() ,它返回一個值列表,而不包含任何鍵。
  • 為剔除重複項,可使用集合(set)。集合:類似於列表,但每個元素都必須是獨一無二的:
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}

print("The following languages have been mentioned:")
for language in set(favorite_languages.values()):
    print(language.title())

 

3.巢狀

  • 有時候,需要將一系列字典儲存在列表中,或將列表作為值儲存在字典中,這稱為巢狀 。你可以在列表中巢狀字典、在字典中巢狀列表甚至在字典中巢狀字典

 

  • 列表中巢狀字典
alien_0 = {'color': 'green', 'points': 5}
alien_1 = {'color': 'yellow', 'points': 10}
alien_2 = {'color': 'red', 'points': 15}

aliens = [alien_0, alien_1, alien_2]

for alien in aliens:
    print(alien)
# 建立一個用於儲存外星人的空列表
aliens = []

# 建立30個綠色的外星人
for alien_number in range(30):
    new_alien = {'color': 'green', 'points': 5, 'speed': 'slow'}
    aliens.append(new_alien)

# 顯示前五個外星人
for alien in aliens[:5]:
    print(alien)
    print("...")

# 顯示建立了多少個外星人
print("Total number of aliens: " + str(len(aliens)))

 

  • 字典中巢狀列表
favorite_languages = {
    'jen': ['python', 'ruby'],
    'sarah': ['c'],
    'edward': ['ruby', 'go'],
    'phil': ['python', 'haskell'],
}

for name, languages in favorite_languages.items():
    print("\n" + name.title() + "'s favorite languages are:")

for language in languages:
    print("\t" + language.title())

 

  • 字典中巢狀字典:下面例子是有多個網站使用者,每個都有獨特的使用者名稱,可在字典中將使用者名稱作為鍵,然後將每位使用者的資訊儲存在
    一個字典中,並將該字典作為與使用者名稱相關聯的值。在下面的程式中,對於每位使用者,我們都儲存了其三項資訊:名、姓和居住地;為訪問這些資訊,我們遍歷所有的使用者名稱,並訪問與每個使用者名稱相關聯的資訊字典
users = {
    'aeinstein': {
        'first': 'albert',
        'last': 'einstein',
        'location': 'princeton',
        },
    'mcurie': {
        'first': 'marie',
        'last': 'curie',
        'location': 'paris',
        },
}

for username, user_info in users.items():
    print("\nUsername: " + username)
    full_name = user_info['first'] + " " + user_info['last']
    location = user_info['location']
    print("\tFull name: " + full_name.title())
    print("\tLocation: " + location.title())
  • 可在字典中巢狀字典,但這樣做時,程式碼可能很快複雜起來。

 

第07章 使用者輸入和while迴圈

1. 函式input() 的工作原理

  • 函式input() 讓程式暫停執行,等待使用者輸入一些文字。獲取使用者輸入後,Python將其儲存在一個變數中,以方便你使用。
message = input("Tell me something, and I will repeat it back to you: ")
print(message)
  • 使用函式input() 時,Python將使用者輸入解讀為字串。
age = input("How old are you? ")    #21
age

#輸出:'21'
  • 可使用函式int() ,它讓Python將輸入轉換為數值
height = input("How tall are you, in inches? ")
height = int(height)

if height >= 36:
    print("\nYou're tall enough to ride!")
else:
    print("\nYou'll be able to ride when you're a little older.")

2. while迴圈

  • 你可以使用while 迴圈來數數,例如,下面的while 迴圈從1數到5:
current_number = 1
while current_number <= 5:
    print(current_number)
    current_number += 1
  • 可使用while 迴圈讓程式在使用者願意時不斷地執行。我們在其中定義了一個退出值,只要使用者輸入的不是這個值,程式就接著執行:
prompt = "\nTell me something, and I will repeat it back to you:"
prompt += "\nEnter 'quit' to end the program. "
message = ""

while message != 'quit':
    message = input(prompt)
    print(message)

 

  • 要立即退出while 迴圈,不再執行迴圈中餘下的程式碼,也不管條件測試的結果如何,可使用break 語句
prompt = "\nPlease enter the name of a city you have visited:"
prompt += "\n(Enter 'quit' when you are finished.) "

while True:
    city = input(prompt)
    if city == 'quit':
        break
    else:
        print("I'd love to go to " + city.title() + "!")
  • 要返回到迴圈開頭,並根據條件測試結果決定是否繼續執行迴圈,可使用continue 語句,它不像break 語句那樣不再執行餘下的程式碼並退出整個迴圈。
current_number = 0

while current_number < 10:
    current_number += 1
    if current_number % 2 == 0:
        continue
    print(current_number)

 

3. 使用while 迴圈來處理列表和字典

  • for 迴圈是一種遍歷列表的有效方式,但在for 迴圈中不應修改列表,否則將導致Python難以跟蹤其中的元素。要在遍歷列表的同時對其進行修改,可使用while 迴圈。通過將while 迴圈同列表和字典結合起來使用,可收集、儲存並組織大量輸入,供以後檢視和顯示。
  • 假設有一個列表,其中包含新註冊但還未驗證的網站使用者;驗證這些使用者後,如何將他們移到另一個已驗證使用者列表中呢?
# 首先,建立一個待驗證使用者列表
# 和一個用於儲存已驗證使用者的空列表
unconfirmed_users = ['alice', 'brian', 'candace']
confirmed_users = []

# 驗證每個使用者,直到沒有未驗證使用者為止
# 將每個經過驗證的列表都移到已驗證使用者列表中
while unconfirmed_users:
    current_user = unconfirmed_users.pop()
    print("Verifying user: " + current_user.title())
    confirmed_users.append(current_user)

# 顯示所有已驗證的使用者
print("\nThe following users have been confirmed:")
for confirmed_user in confirmed_users:
    print(confirmed_user.title())
  • 可使用while迴圈提示使用者輸入任意數量的資訊。下面來建立一個調查程式,其中的迴圈每次執行時都提示輸入被調查者的名字和回答。我們將收集的資料儲存在一個字典中,以便將回答同被調查者關聯起來:
responses = {}

# 設定一個標誌,指出調查是否繼續
polling_active = True
while polling_active:
    # 提示輸入被調查者的名字和回答
    name = input("\nWhat is your name? ")
    response = input("Which mountain would you like to climb someday? ")
    # 將答卷儲存在字典中
    responses[name] = response
    # 看看是否還有人要參與調查
    repeat = input("Would you like to let another person respond? (yes/ no) ")
    if repeat == 'no':
        polling_active = False

# 調查結束,顯示結果
print("\n--- Poll Results ---")
for name, response in responses.items():
    print(name + " would like to climb " + response + ".")

 

第08章 函式

1. 定義函式

  • 使用關鍵字def 來告訴Python你要定義一個函式。這是函式定義 ,向Python指出了函式名,還可能在括號內指出函式為完成其任務需要什麼樣的資訊。定義以冒號結尾。
  • 緊跟在def greet_user(): 後面的所有縮排行構成了函式體。三引號文字是被稱為文件字串 (docstring)的註釋,描述了函式是做什麼的。文件字串用三引號括起,Python使用它們來生成有關程式中函式的文件。
def greet_user():
    """顯示簡單的問候語"""
    print("Hello!")

greet_user()
  • 向函式傳遞資訊
def greet_user(username):
    """顯示簡單的問候語"""
    print("Hello, " + username.title() + "!")

greet_user('jesse')

2. 傳遞實參

  • 鑑於函式定義中可能包含多個形參,因此函式呼叫中也可能包含多個實參。向函式傳遞實參的方式很多,可使用位置實參 ,這要求實參的順序與形參的順序相同;也可使用關鍵字實參 ,其中每個實參都由變數名和值組成;還可使用列表和字典。

 

  • 你呼叫函式時,Python必須將函式呼叫中的每個實參都關聯到函式定義中的一個形參。為此,最簡單的關聯方式是基於實參的順序。這種關聯方式被稱為位置實參 。(和其他語言的函式呼叫類似)

 

  • 關鍵字實參:是傳遞給函式的 名稱-值對。你直接在實參中將名稱和值關聯起來了,因此向函式傳遞實參時不會混淆(不會得到名為Hamster的harry這樣的結果)。關鍵字實參讓你無需考慮函式呼叫中的實參順序,還清楚地指出了函式呼叫中各個值的用途。
def describe_pet(animal_type, pet_name):
    """顯示寵物的資訊"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")

describe_pet(animal_type='hamster', pet_name='harry')

 

  • 編寫函式時,可給每個形參指定預設值 。在呼叫函式中給形參提供了實參時,Python將使用指定的實參值;否則,將使用形參的預設值。因此,給形參指定預設值後,可在函式呼叫中省略相應的實參。使用預設值可簡化函式呼叫,還可清楚地指出函式的典型用法。
def describe_pet(pet_name, animal_type='dog'):
    """顯示寵物的資訊"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")

describe_pet(pet_name='willie')

#輸出:
#I have a dog.
#My dog's name is Willie.
  • 由於給animal_type 指定了預設值,無需通過實參來指定動物型別,因此在函式呼叫中只包含一個實參——寵物的名字。然而,Python依然將這個實參視為位置實參,因此如果函式呼叫中只包含寵物的名字,這個實參將關聯到函式定義中的第一個形參。這就是需要將pet_name 放在形參列表開頭的原因所在。因此可以這樣呼叫:describe_pet('willie')
  • 有時候,需要讓實參變成可選的,這樣使用函式的人就只需在必要時才提供額外的資訊。可使用預設值來讓實參變成可選的。

 

3. 返回值

  • 函式並非總是直接顯示輸出,相反,它可以處理一些資料,並返回一個或一組值。函式返回的值被稱為返回值
  • 在函式中,可使用return 語句將值返回到呼叫函式的程式碼行。返回值讓你能夠將程式的大部分繁重工作移到函式中去完成,從而簡化主程式。

 

  • 返回簡單值:
def get_formatted_name(first_name, last_name):
    """返回整潔的姓名"""
     full_name = first_name + ' ' + last_name
     return full_name.title()

musician = get_formatted_name('jimi', 'hendrix')
print(musician)
  • 返回字典:
def build_person(first_name, last_name):
    """返回一個字典,其中包含有關一個人的資訊"""
    person = {'first': first_name, 'last': last_name}
    return person

musician = build_person('jimi', 'hendrix')
print(musician)

 

4. 傳遞列表

  • 你經常會發現,向函式傳遞列表很有用,這種列表包含的可能是名字、數字或更復雜的物件(如字典)。將列表傳遞給函式後,函式就能直接訪問其內容。下面使用函式來提高處理列表的效率。
  • 將列表傳遞給函式後,函式就可對其進行修改。在函式中對這個列表所做的任何修改都是永久性的,這讓你能夠高效地處理大量的資料。
def print_models(unprinted_designs, completed_models):
    """
    模擬列印每個設計,直到沒有未列印的設計為止
    列印每個設計後,都將其移到列表completed_models中
    """
    while unprinted_designs:
        current_design = unprinted_designs.pop()
        # 模擬根據設計製作3D列印模型的過程
        print("Printing model: " + current_design)
        completed_models.append(current_design)

def show_completed_models(completed_models):
    """顯示列印好的所有模型"""
    print("\nThe following models have been printed:")
    for completed_model in completed_models:
        print(completed_model)

#函式呼叫
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_models = []
print_models(unprinted_designs, completed_models)
show_completed_models(completed_models)

 

  • 有時候,需要禁止函式修改列表。可向函式傳遞列表的副本而不是原件;這樣函式所做的任何修改都隻影響副本,而絲毫不影響原件: function_name(list_name[:])

 

5. 傳遞任意數量的實參

  • 有時候,你預先不知道函式需要接受多少個實參,好在Python允許函式從呼叫語句中收集任意數量的實參。
  • 形參名*toppings 中的星號讓Python建立一個名為toppings 的空元組,並將收到的所有值都封裝到這個元組中。注意,Python將實參封裝到一個元組中,即便函式只收到一個值也如此。
  • 下面的函式只有一個形參*toppings ,但不管呼叫語句提供了多少實參,這個形參都將它們統統收入囊中:
def make_pizza(*toppings):
    """概述要製作的比薩"""
    print("\nMaking a pizza with the following toppings:")
    for topping in toppings:
        print("- " + topping)

make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')

#輸出:
#Making a pizza with the following toppings:
#- pepperoni

#Making a pizza with the following toppings:
#- mushrooms
#- green peppers
#- extra cheese

 

  • 如果要讓函式接受不同型別的實參,必須在函式定義中將接納任意數量實參的形參放在最後。Python先匹配位置實參和關鍵字實參,再將餘下的實參都收集到最後一個形參中。
def make_pizza(size, *toppings):
    """概述要製作的比薩"""
    print("\nMaking a " + str(size) +
        "-inch pizza with the following toppings:")
    for topping in toppings:
        print("- " + topping)

make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

 

  • 使用任意數量的關鍵字實參:有時候,需要接受任意數量的實參,但預先不知道傳遞給函式的會是什麼樣的資訊。在這種情況下,可將函式編寫成能夠接受任意數量的 鍵-值對 ——呼叫語句提供了多少就接受多少。
def build_profile(first, last, **user_info):
    """建立一個字典,其中包含我們知道的有關使用者的一切"""
    profile = {}
    profile['first_name'] = first
    profile['last_name'] = last
    for key, value in user_info.items():
        profile[key] = value
    return profile

user_profile = build_profile('albert', 'einstein',
                              location='princeton',
                              field='physics')
print(user_profile)

 

6. 將函式儲存在模組中

  • 將函式儲存在被稱為模組 的獨立檔案中,再將模組匯入 到主程式中。import 語句允許在當前執行的程式檔案中使用模組中的程式碼。
  • 模組 是副檔名為.py的檔案,包含要匯入到程式中的程式碼。
  • 例子:
    ①我們將檔案pizza.py中,除函式make_pizza() 之外的其他程式碼都刪除。
    ②我們在pizza.py所在的目錄中建立另一個名為making_pizzas.py的檔案。
    ②在這個檔案中用 import pizza 匯入剛建立的模組,然後就可以在裡面通過pizza.funname(),使用pizza.py中的函式了。

 

  • 你還可以匯入模組中的特定函式,這種匯入方法的語法如下:
    from module_name import function_0, function_1, function_2
    這種情況下,不用再用pizza.funname()呼叫,直接function_0()呼叫就好
  • 如果要匯入的函式的名稱可能與程式中現有的名稱衝突,或者函式的名稱太長,可指定簡短而獨一無二的別名 ——函式的另一個名稱,類似於外號:from module_name import function_name as fn
  • 你還可以給模組指定別名。通過給模組指定簡短的別名(如給模組pizza 指定別名p ),讓你能夠更輕鬆地呼叫模組中的函式:
    import module_name as mn

 

  • 使用星號(* )運算子可讓Python匯入模組中的所有函式:from module_name import *
  • 由於匯入了每個函式,可通過名稱來呼叫每個函式,而無需使用句點表示法。
  • 使用並非自己編寫的大型模組時,最好不要採用這種匯入方法:如果模組中有函式的名稱與你的專案中使用的名稱相同,可能導致意想不到的結果:Python可能遇到多個名稱相同的函式或變數,進而覆蓋函式,而不是分別匯入所有的函式。

 

第09章 類

1. 建立和使用類

  • 我們定義了一個名為Dog 的類。
class Dog():
    """一次模擬小狗的簡單嘗試"""
    def __init__(self, name, age):
        """初始化屬性name和age"""
        self.name = name
        self.age = age

    def sit(self):
         """模擬小狗被命令時蹲下"""
        print(self.name.title() + " is now sitting.")

    def roll_over(self):
        """模擬小狗被命令時打滾"""
        print(self.name.title() + " rolled over!")
  • 根據約定,在Python中,首字母大寫的名稱指的是類。
  • 類中的函式稱為方法:你前面學到的有關函式的一切都適用於方法,就目前而言,唯一重要的差別是呼叫方法的方式。
  • 方法__init__():這是一個特殊的方法,每當你根據Dog 類建立新例項時,Python都會自動執行它。在這個方法的名稱中,開頭和末尾各有兩個下劃線,這是一種約定,旨在避免Python預設方法與普通方法發生名稱衝突。
  • 我們將方法__init__() 定義成了包含三個形參:self 、name 和age 。

    在這個方法的定義中,形參self 必不可少,還必須位於其他形參的前面。為何必須在方法定義中包含形參self 呢?因為Python呼叫這個__init__() 方法來建立Dog 例項時,將自動傳入實參self 。

    每個與類相關聯的方法呼叫都自動傳遞實參self ,它是一個指向例項本身的引用,讓例項能夠訪問類中的屬性和方法。
  • 我們建立Dog 例項時,Python將呼叫Dog 類的方法__init__() 。我們將通過實參向Dog() 傳遞名字和年齡;self 會自動傳遞,因此我們不需要傳遞它。每當我們根據Dog 類建立例項時,都只需給最後兩個形參(name 和age )提供值。
  • Dog 類還定義了另外兩個方法:sit() 和roll_over() 。由於這些方法不需要額外的資訊,如名字或年齡,因此它們只有一個形參self。

 

  • 建立一個類的例項(物件):
my_dog = Dog('willie', 6)
print("My dog's name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old.")

 

2. 使用類和例項

  • 類中的每個屬性都必須有初始值,哪怕這個值是0或空字串。
  • 在有些情況下,如設定預設值時,在方法__init__() 內指定這種初始值是可行的;如果你對某個屬性這樣做了,就無需包含為它提供初始值的形參。
class Car():
    def __init__(self, make, model, year):
        """初始化描述汽車的屬性"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0
    def get_descriptive_name(self):
        """返回整潔的描述性資訊"""
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()
    def read_odometer(self):
        """列印一條指出汽車裡程的訊息"""
        print("This car has " + str(self.odometer_reading) + " miles on it.")

#使用類
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()

 

  • 可以以三種不同的方式修改屬性的值:直接通過例項進行修改通過方法進行設定通過方法進行遞增(增加特定的值)。

 

3.繼承

  • 一個類繼承 另一個類時,它將自動獲得另一個類的所有屬性和方法;原有的類稱為父類 ,而新類稱為子類
  • 子類繼承了其父類的所有屬性和方法,同時還可以定義自己的屬性和方法。

 

  • 建立子類時,父類必須包含在當前檔案中,且位於子類前面。
  • super() 是一個特殊函式,幫助Python將父類和子類關聯起來。通過super呼叫父類中的屬性和方法。
  • 讓一個類繼承另一個類後,可新增區分子類和父類所需的新屬性和方法。
  • 對於父類的方法,只要它不符合子類模擬的實物的行為,都可對其進行重寫。為此,可在子類中定義一個這樣的方法,即它與要重寫的父類方法同名。這樣,Python將不會考慮這個父類方法,而只關注你在子類中定義的相應方法。
  • 我們還可以將另一個類的例項用作類的屬性。

 

  • 例子:電動汽車是一種特殊的汽車,因此我們可以在前面建立的Car 類的基礎上建立新類ElectricCar ,這樣我們就只需為電動汽車特有的屬性和行為編寫程式碼。
#父類:Car
class Car():
    """一次模擬汽車的簡單嘗試"""
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0
    def get_descriptive_name(self):
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()
    def read_odometer(self):
        print("This car has " + str(self.odometer_reading) + " miles on it.")
    def update_odometer(self, mileage):
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")
    def increment_odometer(self, miles):
        self.odometer_reading += miles

#另一個類:Battery
class Battery():
    """一次模擬電動汽車電瓶的簡單嘗試"""
    def __init__(self, battery_size=70):
        """初始化電瓶的屬性"""
        self.battery_size = battery_size
    def describe_battery(self):
        """列印一條描述電瓶容量的訊息"""
        print("This car has a " + str(self.battery_size) + "-kWh battery.")
    def get_range(self):
        """列印一條訊息,指出電瓶的續航里程"""
        if self.battery_size == 70:
            range = 240
        elif self.battery_size == 85:
            range = 270
        message = "This car can go approximately " + str(range)
        message += " miles on a full charge."
        print(message)

#子類:ElectricCar
class ElectricCar(Car):
    """電動汽車的獨特之處"""
    def __init__(self, make, model, year):
        """
        初始化父類的屬性,再初始化電動汽車特有的屬性
        """
        super().__init__(make, model, year)
        self.battery = Battery()
    

#使用類
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()

 

4. 匯入類

  • 和函式的操作類似。
  • 可根據需要在程式檔案中匯入任意數量的類。from car import Car, ElectricCar
  • 有時候,需要將類分散到多個模組中,以免模組太大,或在同一個模組中儲存不相關的類。將類儲存在多個模組中時,你可能會發現一個模組中的類依賴於另一個模組中的類。在這種情況下,可在前一個模組中匯入必要的類。

5. Python標準庫

  • Python標準庫 是一組模組,安裝的Python都包含它。

 

  • 字典讓你能夠將資訊關聯起來,但它們不記錄你新增鍵-值對的順序。要建立字典並記錄其中的鍵-值對的新增順序,可使用模組collections 中的OrderedDict類。OrderedDict 例項的行為幾乎與字典相同,區別只在於記錄了鍵-值對的新增順序。
from collections import OrderedDict

favorite_languages = OrderedDict()
favorite_languages['jen'] = 'python'
favorite_languages['sarah'] = 'c'
favorite_languages['edward'] = 'ruby'
favorite_languages['phil'] = 'python'

for name, language in favorite_languages.items():
    print(name.title() + "'s favorite language is " +
        language.title() + ".")
  • 類名應採用駝峰命名法 ,即將類名中的每個單詞的首字母都大寫,而不使用下劃線。例項名和模組名都採用小寫格式,並在單詞之間加上下劃線。
  • 對於每個類,都應緊跟在類定義後面包含一個文件字串。每個模組也都應包含一個文件字串,對其中的類可用於做什麼進行描述。
  • 在類中,可使用一個空行來分隔方法;而在模組中,可使用兩個空行來分隔類。
  • 需要同時匯入標準庫中的模組和你編寫的模組時,先編寫匯入標準庫模組的import 語句,再新增一個空行,然後編寫匯入你自己編寫的模組的import 語句。

 

第10章 檔案和異常

1. 從檔案中讀取資料

  • 要以任何方式使用檔案——哪怕僅僅是列印其內容,都得先開啟 檔案,這樣才能訪問它。函式open()接受一個引數:要開啟的檔案的名稱。Python在當前執行的檔案所在的目錄中查詢指定的檔案。函式open() 返回一個表示檔案的物件。
  • 關鍵字with 在不再需要訪問檔案後將其關閉(隱式地呼叫close()函式)。使用關鍵字with 時,open() 返回的檔案物件只在with 程式碼塊內可用。
  • 你也可以呼叫open() 和close() 來開啟和關閉檔案,但這樣做時,如果程式存在bug,導致close() 語句未執行,檔案將不會關閉。
  • 有了表示檔案的物件後,我們使用方法read() 來讀取這個檔案的全部內容。
  • read() 到達檔案末尾時返回一個空字串,而將這個空字串顯示出來時就是一個空行。要刪除多出來的空行,可在print 語句中使用rstrip() 。
with open('pi_digits.txt') as file_object:
    contents = file_object.read()
    print(contents)
  • 有時候檔案不在程式目錄下,可寫出完整路徑去尋找:
file_path = 'C:\Users\ehmatthes\other_files\text_files\filename.txt'
with open(file_path) as file_object:
  • 要以每次一行的方式檢查檔案,可對檔案物件使用for 迴圈。
filename = 'pi_digits.txt'
with open(filename) as file_object:
    for line in file_object:
    print(line)

 

  • 可在with 程式碼塊內將檔案的各行儲存在一個列表中,並在with 程式碼塊外使用該列表:這樣你可以立即處理檔案的各個部分,也可推遲到程式後面再處理。
  • 方法readlines() 從檔案中讀取每一行,並將其儲存在一個列表中。
filename = 'pi_digits.txt'
with open(filename) as file_object:
    lines = file_object.readlines()

for line in lines:
    print(line.rstrip())

 

2. 寫入檔案

  • 要將文字寫入檔案,你在呼叫open() 時需要提供另一個實參'w',告訴Python你要寫入開啟的檔案。
  • 呼叫open() 時提供了兩個實參。第一個實參也是要開啟的檔案的名稱;第二個實參('w' )告訴Python,我們要以寫入模式 開啟這個檔案。
  • 開啟檔案時,可指定讀取模式 ('r' )、寫入模式 ('w' )、附加模式 ('a' )或讓你能夠讀取和寫入檔案的模式('r+' )。如果你省略了模式實參,Python將以預設的只讀模式開啟檔案。
  • 如果你要寫入的檔案不存在,函式open() 將自動建立它。然而,以寫入('w' )模式開啟檔案時千萬要小心,因為如果指定的檔案已經存在,Python將在返回檔案物件前清空該檔案。
  • 如果你要給檔案新增內容,而不是覆蓋原有的內容,可以附加模式 開啟檔案。
  • Python只能將字串寫入文字檔案。要將數值資料儲存到文字檔案中,必須先使用函式str() 將其轉換為字串格式。
filename = 'programming.txt'
with open(filename, 'w') as file_object:
    file_object.write("I love programming.")

 

3. 異常

  • Python使用被稱為異常特殊物件來管理程式執行期間發生的錯誤。
  • 發生錯誤時,如果你編寫了處理該異常的程式碼,程式將繼續執行;如果你未對異常進行處理,程式將停止,並顯示一個traceback,其中包含有關異常的報告。
  • 當你認為可能發生了錯誤時,可編寫一個try-except 程式碼塊來處理可能引發的異常。你讓Python嘗試執行一些程式碼,並告訴它如果這些程式碼引發了指定的異常,該怎麼辦。
try:
    print(5/0)
except ZeroDivisionError:
    print("You can't divide by zero!")

4. 儲存資料

  • 模組json 讓你能夠將簡單的Python資料結構轉儲到檔案中,並在程式再次執行時載入該檔案中的資料。
  • 你還可以使用json 在Python程式之間分享資料。更重要的是,JSON資料格式並非Python專用的,這讓你能夠將以JSON格式儲存的資料與使用其他程式語言的人分享。這是一種輕便格式,很有用,也易於學習。
    JSON(JavaScript Object Notation)格式最初是為JavaScript開發的,但隨後成了一種常見格式,被包括Python在內的眾多語言採用。

 

  • 函式json.dump() 接受兩個實參:要儲存的資料以及可用於儲存資料的檔案物件。
import json
numbers = [2, 3, 5, 7, 11, 13]
filename = 'numbers.json'

with open(filename, 'w') as f_obj:
    json.dump(numbers, f_obj)
  • 再使用函式json.load() 載入儲存在numbers.json中的資訊,並將其儲存到變數numbers 中。
import json
filename = 'numbers.json'
with open(filename) as f_obj:
   numbers = json.load(f_obj)
print(numbers)

 

第11章 測試程式碼

1. 測試函式

  • 下面是一段手動測試函式的程式碼
def get_formatted_name(first, last):
    """Generate a neatly formatted full name."""
    full_name = first + ' ' + last
    return full_name.title()
    
print("Enter 'q' at any time to quit.")
while True:
    first = input("\nPlease give me a first name: ")
    if first == 'q':
        break
    last = input("Please give me a last name: ")
    if last == 'q':
        break
    formatted_name = get_formatted_name(first, last)
    print("\tNeatly formatted name: " + formatted_name + '.')

 

  • Python中有模組unittest,專門用於測試。
  • 下面是一個只包含一個方法的測試用例,它檢查函式get_formatted_name() 在給定名和姓時能否正確地工作。(通常測試檔案和函式檔案最好是兩個檔案,這裡為了方便看放一起了)
import unittest

def get_formatted_name(first, last):
    """Generate a neatly formatted full name."""
    full_name = first + ' ' + last
    return full_name.title()
    
class NamesTestCase(unittest.TestCase):
    """測試name_function.py"""
    def test_first_last_name(self):
        """能夠正確地處理像Janis Joplin這樣的姓名嗎?"""
        formatted_name = get_formatted_name('janis', 'joplin')
        self.assertEqual(formatted_name, 'Janis Joplin')
    
unittest.main()
  • 我們建立了一個名為NamesTestCase 的類,用於包含一系列針對get_formatted_name() 的單元測試。你可隨便給這個類命名,但最好讓它看起來與要測試的函式相關,幷包含字樣Test。這個類必須繼承unittest.TestCase 類,這樣Python才知道如何執行你編寫的測試。
  • NamesTestCase 只包含一個方法,用於測試get_formatted_name() 的一個方面。我們將這個方法命名為test_first_last_name() ,因為我們要核實的是隻有名和姓的姓名能否被正確地格式化。
  • 我們執行時,所有以test 打頭的方法都將自動執行。在這個方法中,我們呼叫了要測試的函式,並儲存了要測試的返回值。在這個示例中,我們使用實參'janis' 和'joplin' 呼叫get_formatted_name() ,並將結果儲存到變數formatted_name 中。
  • 在這裡,我們知道get_formatted_name() 應返回這樣的姓名,即名和姓的首字母為大寫,且它們之間有一個空格,因此我們期望formatted_name 的值為Janis Joplin 。為檢查是否確實如此,我們呼叫unittest的方法assertEqual() ,並向它傳遞formatted_name 和'Janis Joplin' 。程式碼行self.assertEqual(formatted_name, 'Janis Joplin') 的意思是說:“將formatted_name 的值同字串'Janis Joplin' 進行比較,如果它們相等,就萬事大吉,如果它們不相等,跟我說一聲!”

2. 測試類

  • Python在unittest.TestCase 類中提供了很多斷言方法。前面說過,斷言方法檢查你認為應該滿足的條件是否確實滿足。如果該條件確實滿足,你對程式行為的假設就得到了確認,你就可以確信其中沒有錯誤。如果你認為應該滿足的條件實際上並不滿足,Python將引發異常。

  • 我們首先匯入了模組unittest 以及要測試的類AnonymousSurvey 。我們將測試用例命名為TestAnonymousSurvey ,它也繼承了unittest.TestCase。第一個測試方法驗證調查問題的單個答案被儲存後,會包含在調查結果列表中。對於這個方法,一個不錯的描述性名稱是test_store_single_response() 。如果這個測試未通過,我們就能通過輸出中的方法名得知,在儲存單個調查答案方面存在問題。
    要測試類的行為,需要建立其例項。我們使用問題"What language did you first learn to speak?" 建立了一個名為my_survey 的例項,然後使用方法store_response() 儲存了單個答案English 。接下來,我們檢查English 是否包含在列表my_survey.responses 中,以核實這個答案是否被妥善地儲存了
import unittest
from survey import AnonymousSurvey

class TestAnonmyousSurvey(unittest.TestCase):
    """針對AnonymousSurvey類的測試"""
    def test_store_single_response(self):
        """測試單個答案會被妥善地儲存"""
        question = "What language did you first learn to speak?"
        my_survey = AnonymousSurvey(question)
        my_survey.store_response('English')
        self.assertIn('English', my_survey.responses)

unittest.main()

相關文章