日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python基础入门知识(11)

發布時間:2023/12/20 python 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python基础入门知识(11) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

接前面的文章:

Python基礎入門教學

  • 2 Python的基礎知識
    • 2.15 文件和異常
      • 2.15.4 存儲數據
        • 2.15.4.1 使用json.dump()和json.load()
        • 2.15.4.2 保存和讀取用戶生成的數據
        • 2.15.4.3 重構
    • 2.16 測試代碼
      • 2.16.1 測試函數
        • 2.16.1.1 單元測試和測試用例
        • 2.16.1.2 可通過的測試
        • 2.16.1.3 不能通過的測試
        • 2.16.1.4 測試未通過時怎么辦
        • 2.16.1.5 添加新測試

2 Python的基礎知識

2.15 文件和異常

2.15.4 存儲數據

很多程序都要求用戶輸入某種信息,如讓用戶存儲游戲首選項或提供要可視化的數據。不管專注的是什么,程序都把用戶提供的信息存儲在列表和字典等數據結構中。用戶關閉程序時,我們幾乎總是要保存他們提供的信息;一種簡單的方式是使用模塊json來存儲數據。
模塊json讓我們能夠將簡單的Python數據結構轉儲到文件中,并在程序再次運行時加載該文件中的數據。我們還可以使用json在Python程序之間分享數據。更重要的是,JSON數據格式并非Python專用的,這讓我們能夠將以JSON格式存儲的數據與使用其他編程語言的人分享。這是一種輕便格式,很有用,也易于學習。

  • 注意:JSON(JavaScript Object Notation)格式最初是為JavaScript開發的,但隨后成了一種常見格式,被包括Python在內的眾多語言采用。

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

我們來編寫一個存儲一組數字的簡短程序,再編寫一個將這些數字讀取到內存中的程序。第一個程序將使用json.dump()來存儲這組數字,而第二個程序將使用json.load()。
函數json.dump()接受兩個實參:要存儲的數據以及可用于存儲數據的文件對象。下面演示了如何使用json.dump()來存儲數字列表:
number_writer.py

import json numbers = [2, 3, 5, 7, 11, 13] filename = 'number.json' ? with open(filename, 'w') as f_obj: ?json.dump(numbers,f_obj)?

我們先導入模塊json,再創建一個數字列表。在?處,我們指定了要將該數字列表存儲到其中的文件的名稱。通常使用文件擴展名.json來指出文件存儲的數據為JSON格式。接下來,我們以寫入模式打開這個文件,讓json能夠將數據寫入其中(見?)。在?處,我們使用函數json.dump()將數字列表存儲到文件numbers.json中。
這個程序沒有輸出,但我們可以打開文件numbers.json,看看其內容。數據的存儲格式與Python中一樣:

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

下面再編寫一個程序,使用json.load()將這個列表讀取到內存中:
number_reader.py

import json filename = 'number.json' ? with open(filename) as f_obj: ?numbers = json.load(f_obj) ? print(numbers)

在?處,我們確保讀取的是前面寫入的文件。這次我們以讀取方式打開這個文件,因為Python只需讀取這個文件(見?)。在?處,我們使用函數json.load()加載存儲在numbers.json中的信息,并將其存儲到變量numbers中。最后,我們打印恢復的數字列表,看看它是否與number_writer.py中創建的數字列表相同:

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

這是一種在程序之間共享數據的簡單方式。

2.15.4.2 保存和讀取用戶生成的數據

對于用戶生成的數據,使用json保存它們大有裨益,因為如果不以某種方式進行存儲,等程序停止運行時用戶的信息將丟失。下面來看一個這樣的例子:用戶首次運行程序時被提示輸入自己的名字,這樣再次運行程序時就記住他了。
我們先來存儲用戶的名字:
remember_me.py

import json username = input("Whit is your name? ") ? filename = 'username.json' with open(filename, 'w') as f_obj:json.dump(username, f_obj) ?print("We'll remember you when you come back, "+username+"!") ?

在?處,我們提示輸入用戶名,并將其存儲在一個變量中。接下來,我們調用json.dump(),并將用戶名和一個文件對象傳遞給它,從而將用戶名存儲到文件中(見?)。然后,我們打印一條消息,指出我們存儲了他輸入的信息(見?):

Whit is your name? shirley We'll remember you when you come back, shirley!

現在再編寫一個程序,向其名字被存儲的用戶發出問候:
greet_user.py

import json filename = 'username.json' with open(filename) as f_obj:username = json.load(f_obj) ?print("Welcome back,"+username+"!") ?

在?處,我們使用json.load()將存儲在username.json中的信息讀取到變量username中。恢復用戶名后,我們就可以歡迎用戶回來了(見?):

Welcome back,shirley!

我們需要將這兩個程序合并到一個程序(remember_me.py)中。這個程序運行時,我們將嘗試從文件username.json中獲取用戶名,因此我們首先編寫一個嘗試恢復用戶名的try代碼塊。如果這個文件不存在,我們就在except代碼塊中提示用戶輸入用戶名,并將其存儲在username.json中,以便程序再次運行時能夠獲取它:
remember_me.py

import json # 如果以前存儲了用戶名,就加載它 # 否則,就提示用戶輸入用戶名并存儲它 filename = 'username.json' try:with open(filename) as f_obj: ?username = json.load(f_obj) ? except FileNotFoundError: ?username = input("Whit is your name? ") ?with open(filename, 'w') as f_obj: ?json.dump(username, f_obj)print("We'll remember you when you come back, "+username+"!") else:print("Welcome back,"+username+"!")

這里沒有任何新代碼,只是將前兩個示例的代碼合并到了一個程序中。在?處,我們嘗試打開文件username.json。如果這個文件存在,就將其中的用戶名讀取到內存中(見?),再執行else代碼塊,即打印一條歡迎用戶回來的消息。用戶首次運行這個程序時,文件username.json不存在,將引發FileNotFoundError異常(見?),因此Python將執行except代碼塊:提示用戶輸入其用戶名(見?),再使用json.dump()存儲該用戶名,并打印一句問候語(見?)。
無論執行的是except代碼塊還是else代碼塊,都將顯示用戶名和合適的問候語。如果這個程序是首次運行,輸出將如下:

Whit is your name? shirley We'll remember you when you come back, shirley!

否則,輸出將如下:

Welcome back,shirley!

這是程序之前至少運行了一次時的輸出。

2.15.4.3 重構

我們經常會遇到這樣的情況:代碼能夠正確地運行,但可做進一步的改進——將代碼劃分為一系列完成具體工作的函數。這樣的過程被稱為重構。重構讓代碼更清晰、更易于理解、更容易擴展。
要重構remember_me.py,可將其大部分邏輯放到一個或多個函數中。remember_me.py的重點是問候用戶,因此我們將其所有代碼都放到一個名為greet_user()的函數中:
remember_me.py

import json def greet_user():"""問候用戶,并指出其名字""" ?filename = 'username.json'try:with open(filename) as f_obj:username = json.load(f_obj)except FileNotFoundError:username = input("Whit is your name? ")with open(filename, 'w') as f_obj:json.dump(username, f_obj)print("We'll remember you when you come back, "+username+"!")else:print("Welcome back,"+username+"!") greet_user()

考慮到現在使用了一個函數,我們刪除了注釋,轉而使用一個文檔字符串來指出程序是做什么的(見?)。這個程序更清晰些,但函數greet_user()所做的不僅僅是問候用戶,還在存儲了用戶名時獲取它,而在沒有存儲用戶名時提示用戶輸入一個。
下面來重構greet_user(),讓它不執行這么多任務。為此,我們首先將獲取存儲的用戶名的代碼移到另一個函數中:

import json def get_stored_username():"""如果存儲了用戶名,就獲取它""" ?filename = 'username.json'try:with open(filename) as f_obj:username = json.load(f_obj)except FileNotFoundError:return None ?else:return username def greet_user():"""問候用戶,并指出其名字"""username = get_stored_username()if username: ?print("Welcome back," + username + "!")else:username = input("Whit is your name? ")filename = 'username.json'with open(filename, 'w') as f_obj:json.dump(username, f_obj)print("We'll remember you when you come back, "+username+"!") greet_user()

新增的函數get_stored_username()目標明確,?處的文檔字符串指出了這一點。如果存儲了用戶名,這個函數就獲取并返回它;如果文件username.json不存在,這個函數就返回None(見?)。這是一種不錯的做法:函數要么返回預期的值,要么返回None;這讓我們能夠使用函數的返回值做簡單測試。在?處,如果成功地獲取了用戶名,就打印一條歡迎用戶回來的消息,否則就提示用戶輸入用戶名。
我們還需將greet_user()中的另一個代碼塊提取出來:將沒有存儲用戶名時提示用戶輸入的代碼放在一個獨立的函數中:

import json def get_stored_username():"""如果存儲了用戶名,就獲取它"""filename = 'username.json'try:with open(filename) as f_obj:username = json.load(f_obj)except FileNotFoundError:return Noneelse:return username def get_new_username():"""提示用戶輸入用戶名"""username = input("What is your name? ")filename = 'username.json'with open(filename, 'w') as f_obj:json.dump(username, f_obj)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()

在remember_me.py的這個最終版本中,每個函數都執行單一而清晰的任務。我們調用greet_user(),它打印一條合適的消息:要么歡迎老用戶回來,要么問候新用戶。為此,它首先調用get_stored_username(),這個函數只負責獲取存儲的用戶名(如果存儲了的話),再在必要時調用get_new_username(),這個函數只負責獲取并存儲新用戶的用戶名。要編寫出清晰而易于維護和擴展的代碼,這種劃分工作必不可少。

2.16 測試代碼

編寫函數或類時,還可為其編寫測試。通過測試,可確定代碼面對各種輸入都能夠按要求的那樣工作。測試讓我們信心滿滿,深信即便有更多的人使用我們的程序,它也能正確地工作。在程序中添加新代碼時,我們也可以對其進行測試,確認它們不會破壞程序既有的行為。程序員都會犯錯,因此每個程序員都必須經常測試其代碼,在用戶發現問題前找出它們。

2.16.1 測試函數

要學習測試,得有要測試的代碼。下面是一個簡單的函數,它接受名和姓并返回整潔的姓名:name_function.py

def get_formatted_name(first, last):"""Generate a neatly formatted full name."""full_name = first+' '+lastreturn full_name.title()

函數get_formatted_name()將名和姓合并成姓名,在名和姓之間加上一個空格,并將它們的首字母都大寫,再返回結果。為核實get_formatted_name()像期望的那樣工作,我們來編寫一個使用這個函數的程序。程序names.py讓用戶輸入名和姓,并顯示整潔的全名:
names.py

from name_function import get_formatted_name print("Enter 'q' at any time to quit.'") while True:first = input("\nPlease give me a first name: ")if first == 'q':breaklast = input("Please give me a last name: ")if last == 'q':breakformatted_name = get_formatted_name(first, last)print("\tNeatly formatted name: "+formatted_name+'.')

這個程序從name_function.py中導入get_formatted_name()。用戶可輸入一系列的名和姓,并看到格式整潔的全名:

Enter 'q' at any time to quit.'Please give me a first name: janis Please give me a last name: joplinNeatly formatted name: Janis Joplin.Please give me a first name: bob Please give me a last name: dylanNeatly formatted name: Bob Dylan.Please give me a first name: q

從上述輸出可知,合并得到的姓名正確無誤。現在假設我們要修改get_formatted_name(),使其還能夠處理中間名。這樣做時,我們要確保不破壞這個函數處理只有名和姓的姓名的方式。為此,我們可以在每次修改get_formatted_name()后都進行測試:運行程序names.py,并輸入像JanisJoplin這樣的姓名,但這太煩瑣了。所幸Python提供了一種自動測試函數輸出的高效方式。倘若我們對get_formatted_name()進行自動測試,就能始終信心滿滿,確信給這個函數提供我們測試過的姓名時,它都能正確地工作。

2.16.1.1 單元測試和測試用例

Python標準庫中的模塊unittest提供了代碼測試工具。
單元測試用于核實函數的某個方面沒有問題;
測試用例是一組單元測試,這些單元測試一起核實函數在各種情形下的行為都符合要求。良好的測試用例考慮到了函數可能收到的各種輸入,包含針對所有這些情形的測試。
全覆蓋式測試用例包含一整套單元測試,涵蓋了各種可能的函數使用方式。對于大型項目,要實現全覆蓋可能很難。通常,最初只要針對代碼的重要行為編寫測試即可,等項目被廣泛使用時再考慮全覆蓋。

2.16.1.2 可通過的測試

創建測試用例的語法需要一段時間才能習慣,但測試用例創建后,再添加針對函數的單元測試就很簡單了。要為函數編寫測試用例,可先導入模塊unittest以及要測試的函數,再創建一個繼承unittest.TestCase的類,并編寫一系列方法對函數行為的不同方面進行測試。
下面是一個只包含一個方法的測試用例,它檢查函數get_formatted_name()在給定名和姓時能否正確地工作:
test_name_function.py

import unittest from name_function import get_formatted_name 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()

首先,我們導入了模塊unittest和要測試的函數get_formatted_name()。在?處,我們創建了一個名為NamesTestCase的類,用于包含一系列針對get_formatted_name()的單元測試。我們可隨便給這個類命名,但最好讓它看起來與要測試的函數相關,并包含字樣Test。這個類必須繼承unittest.TestCase類,這樣Python才知道如何運行我們編寫的測試。
NamesTestCase只包含一個方法,用于測試get_formatted_name()的一個方面。我們將這個方法命名為test_first_last_name(),因為我們要核實的是只有名和姓的姓名能否被正確地格式化。我們運行testname_function.py時,所有以test打頭的方法都將自動運行。在這個方法中,我們調用了要測試的函數,并存儲了要測試的返回值。在這個示例中,我們使用實參’janis’和’joplin’調用get_formatted_name(),并將結果存儲到變量formatted_name中(見?)。
在?處,我們使用了unittest類最有用的功能之一:一個斷言方法。斷言方法用來核實得到的結果是否與期望的結果一致。在這里,我們知道get_formatted_name()應返回這樣的姓名,即名和姓的首字母為大寫,且它們之間有一個空格,因此我們期望formatted_name的值為Janis Joplin。為檢查是否確實如此,我們調用unittest的方法assertEqual(),并向它傳遞formatted_name和’Janis Joplin’。代碼行self.assertEqual(formatted_name, ‘Janis Joplin’)的意思是說:“將formatted_name的值同字符串’Janis Joplin’進行比較,如果它們相等,就萬事大吉,如果它們不相等,跟我說一聲!”
代碼行unittest.main()讓Python運行這個文件中的測試。運行test_name_function.py時,得到的輸出如下:

. ---------------------------------------------------------------------- Ran 1 tests in 0.000sOK

第1行的句點表明有一個測試通過了。接下來的一行指出Python運行了一個測試,消耗的時間不到0.001秒。最后的OK表明該測試用例中的所有單元測試都通過了。上述輸出表明,給定包含名和姓的姓名時,函數get_formatted_name()總是能正確地處理。修改get_formatted_name()后,可再次運行這個測試用例。如果它通過了,我們就知道在給定Janis Joplin這樣的姓名時,這個函數依然能夠正確地處理。

2.16.1.3 不能通過的測試

測試未通過時結果是什么樣的呢?我們來修改get_formatted_name(),使其能夠處理中間名,但這樣做時,故意讓這個函數無法正確地處理像Janis Joplin這樣只有名和姓的姓名。
下面是函數get_formatted_name()的新版本,它要求通過一個實參指定中間名:

def get_formatted_name(first, middle, last):"""生成整潔地姓名"""full_name = first+' '+middle+' '+lastreturn full_name.title()

這個版本應該能夠正確地處理包含中間名的姓名,但對其進行測試時,我們發現它再也不能正確地處理只有名和姓的姓名。這次運行程序test_name_function.py時,輸出如下:

E ? ====================================================================== ERROR: test_first last_name(_main_.NamesTestCase) ? Traceback (most recent call last): ?File"test_name_function.py",line 8,in test_first_last_nameformatted name = get_formatted_name('janis','joplin') TypeError: get_formatted_name() missing 1 required positional argumen t:'last" ---------------------------------------------------------------------- Ran 1 test in 0. 000s ? FAILED(errors=1) ?

其中包含的信息很多,因為測試未通過時,需要讓我們知道的事情可能有很多。第1行輸出只有一個字母E(見?),它指出測試用例中有一個單元測試導致了錯誤。接下來,我們看到NamesTestCase中的test_first_last_name()導致了錯誤(見?)。測試用例包含眾多單元測試時,知道哪個測試未通過至關重要。在?處,我們看到了一個標準的traceback,它指出函數調用get_formatted_name(‘janis’,‘joplin’)有問題,因為它缺少一個必不可少的位置實參。
我們還看到運行了一個單元測試(見?)。最后,還看到了一條消息,它指出整個測試用例都未通過,因為運行該測試用例時發生了一個錯誤(見?)。這條消息位于輸出末尾,讓我們一眼就能看到——我們可不希望為獲悉有多少測試未通過而翻閱長長的輸出。

2.16.1.4 測試未通過時怎么辦

測試未通過時怎么辦呢?如果我們檢查的條件沒錯,測試通過了意味著函數的行為是對的,而測試未通過意味著我們編寫的新代碼有錯。因此,測試未通過時,不要修改測試,而應修復導致測試不能通過的代碼:檢查剛對函數所做的修改,找出導致函數行為不符合預期的修改。
在這個示例中,get_formatted_name()以前只需要兩個實參——名和姓,但現在它要求提供名、中間名和姓。新增的中間名參數是必不可少的,這導致get_formatted_name()的行為不符合預期。就這里而言,最佳的選擇是讓中間名變為可選的。這樣做后,使用類似于Janis Joplin的姓名進行測試時,測試就會通過了,同時這個函數還能接受中間名。下面來修改get_formatted_name(),將中間名設置為可選的,然后再次運行這個測試用例。如果通過了,我們接著確認這個函數能夠妥善地處理中間名。
要將中間名設置為可選的,可在函數定義中將形參middle移到形參列表末尾,并將其默認值指定為一個空字符串。我們還要添加一個if測試,以便根據是否提供了中間名相應地創建姓名:

def get_formatted_name(first, last, middle=''):"""生成整潔地姓名"""if middle:full_name = first+' '+middle+' '+lastelse:full_name = first+' '+lastreturn full_name.title()

在get_formatted_name()的這個新版本中,中間名是可選的。如果向這個函數傳遞了中間名(if middle:),姓名將包含名、中間名和姓,否則姓名將只包含名和姓。現在,對于兩種不同的姓名,這個函數都應該能夠正確地處理。為確定這個函數依然能夠正確地處理像Janis Joplin這樣的姓名,我們再次運行test_name_function.py:

. ---------------------------------------------------------------------- Ran 1 tests in 0.000sOK

現在,測試用例通過了。太好了,這意味著這個函數又能正確地處理像JanisJoplin這樣的姓名了,而且我們無需手工測試這個函數。這個函數很容易就修復了,因為未通過的測試讓我們得知新代碼破壞了函數原來的行為。

2.16.1.5 添加新測試

確定get_formatted_name()又能正確地處理簡單的姓名后,我們再編寫一個測試,用于測試包含中間名的姓名。為此,我們在NamesTestCase類中再添加一個方法:

import unittest from name_function import get_formatted_name 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')def test_first_last_middle_name(self):"""能夠正確地處理像Wolfgang Amadeus Mozart這樣的姓名嗎?"""formatted_name = get_formatted_name( ?'wolfgang','mozart','amadeus')self.assertEqual(formatted_name,'Wolfgang Amadeus Mozart') unittest.main()

我們將這個方法命名為test_first_last_middle_name()。方法名必須以test_打頭,這樣它才會在我們運行test_name_function.py時自動運行。這個方法名清楚地指出了它測試的是get_formatted_name()的哪個行為,這樣,如果該測試未通過,我們就會馬上知道受影響的是哪種類型的姓名。在TestCase類中使用很長的方法名是可以的;這些方法的名稱必須是描述性的,這才能讓我們明白測試未通過時的輸出;這些方法由Python自動調用,我們根本不用編寫調用它們的代碼。
為測試函數get_formatted_name(),我們使用名、姓和中間名調用它(見?),再使用assertEqual()檢查返回的姓名是否與預期的姓名(名、中間名和姓)一致。我們再次運行test_name_function.py時,兩個測試都通過了:

.. ---------------------------------------------------------------------- Ran 2 tests in 0.000sOK

太好了!現在我們知道,這個函數又能正確地處理像Janis Joplin這樣的姓名了,我們還深信它也能夠正確地處理像Wolfgang Amadeus Mozart這樣的姓名。

后續更新:

總結

以上是生活随笔為你收集整理的Python基础入门知识(11)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。