在Python編程過程中用單元測(cè)試法調(diào)試代碼的介紹
對(duì)于程序開發(fā)新手來(lái)說(shuō),一個(gè)最常見的困惑是測(cè)試的主題。他們隱約覺得“單元測(cè)試”是很好的,而且他們也應(yīng)該做單元測(cè)試。但他們卻不懂這個(gè)詞的真正含義。如果這聽起來(lái)像是在說(shuō)你,不要怕!在這篇文章中,我將介紹什么是單元測(cè)試,為什么它有用,以及如何對(duì)Python的代碼進(jìn)行單元測(cè)試。
什么是測(cè)試?
在討論為什么測(cè)試很有用、怎樣進(jìn)行測(cè)試之前,讓我們先花幾分鐘來(lái)定義一下“單元測(cè)試”究竟是什么。在一般的編程術(shù)語(yǔ)中,“測(cè)試”指的是通過編寫可以調(diào)用的代碼(獨(dú)立于你實(shí)際應(yīng)用程序的代碼)來(lái)幫助你確定程序中是否有錯(cuò)誤。這并不能證明你的代碼是正確的(在非常有限的情況下這是唯一的可能)。它只是報(bào)告了測(cè)試者認(rèn)為的那種情況是否被正確處理了。
注:當(dāng)我使用“測(cè)試”一次時(shí),我指的是“自動(dòng)化測(cè)試”,即這些測(cè)試是在機(jī)器上運(yùn)行的?!笆謩?dòng)測(cè)試”則是一個(gè)人運(yùn)行程序,并與它進(jìn)行交互,從而發(fā)現(xiàn)漏洞,這是個(gè)獨(dú)立的概念。
測(cè)試可以檢查出什么樣的情況呢?語(yǔ)法錯(cuò)誤是語(yǔ)言的意外誤用,如
my_list..append(foo)
后面多余的一個(gè) “.“。邏輯錯(cuò)誤是當(dāng)算法(可以看成是“解決問題的方式”)不正確時(shí)引發(fā)的??赡艹绦騿T忘記Python是“零索引“的并且試圖通過寫
print(my_string[len(my_string)])
(這樣會(huì)引起IndexError)來(lái)打印出一個(gè)字符串中的最后一個(gè)字符。更大、更系統(tǒng)的錯(cuò)誤也可以被檢查出來(lái)。比如當(dāng)用戶輸入一個(gè)大于100的數(shù)字、或者在網(wǎng)站檢索不可用的時(shí)候掛起此網(wǎng)站的話,程序會(huì)一直崩潰。
這些所有的錯(cuò)誤都可以通過對(duì)代碼的仔細(xì)測(cè)試檢查出來(lái)。Unit testing,特指在一個(gè)分隔的代碼單元中的測(cè)試。一個(gè)單元可以是整個(gè)模塊,一個(gè)單獨(dú)的類或者函數(shù),或者這兩者間的任何代碼。然而,重要的是,測(cè)試代碼要與我們沒有測(cè)試到的其他代碼相互隔離(因?yàn)槠渌a本身有錯(cuò)誤的話會(huì)因此混淆測(cè)試結(jié)果)。考慮如下例子:
def is_prime(number): """Return True if *number* is prime.""" for element in range(number): if number % element == 0: return False return True def print_next_prime(number): """Print the closest prime number larger than *number*.""" index = number while True: index += 1 if is_prime(index): print(index)
你有兩個(gè)函數(shù),is_prime和print_next_prime。如果你想測(cè)試print_next_prime,我們就需要確定is_prime是正確的,因?yàn)閜rint_next_prime中調(diào)用了這個(gè)函數(shù)。在這種情況下,print_next_prime函數(shù)是一個(gè)單元,is_prime函數(shù)是另一個(gè)單元。由于單元測(cè)試每次只測(cè)試一個(gè)單元,因此我們需要仔細(xì)考慮怎樣才能準(zhǔn)確的測(cè)試print_next_prime?(更多的是關(guān)于之后怎樣實(shí)現(xiàn)這些測(cè)試)。
因此,測(cè)試代碼應(yīng)該長(zhǎng)什么樣呢?如果上一個(gè)例子存在一個(gè)叫primes.py的文件中,我們可以把測(cè)試代碼寫在一個(gè)叫test_primes.py的文件中。下面是test_primes.py 中的最基本內(nèi)容,比如下面這個(gè)測(cè)試樣例:
import unittest from primes import is_prime class PrimesTestCase(unittest.TestCase): """Tests for `primes.py`.""" def test_is_five_prime(self): """Is five successfully determined to be prime?""" self.assertTrue(is_prime(5)) if __name__ == '__main__': unittest.main()
這個(gè)文件通過一個(gè)test case :? test_is_five_prime. 創(chuàng)建了一個(gè)單元測(cè)試。通過Python內(nèi)嵌的一個(gè)測(cè)試框架unittest。當(dāng)unittest.main()被調(diào)用時(shí),任何一個(gè)以test開頭命名的成員函數(shù)將被運(yùn)行,他們是unittest.TestCase的一個(gè)派生類,并且是斷言檢查的。如果我們通過輸入python test_primes.py來(lái)運(yùn)行測(cè)試,我們能夠看到unittest框架在控制臺(tái)上 的輸出:
$ python test_primes.py E ====================================================================== ERROR: test_is_five_prime (__main__.PrimesTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_primes.py", line 8, in test_is_five_prime self.assertTrue(is_prime(5)) File "/home/jknupp/code/github_code/blug_private/primes.py", line 4, in is_prime if number % element == 0: ZeroDivisionError: integer division or modulo by zero ---------------------------------------------------------------------- Ran 1 test in 0.000s
單獨(dú)的“E”表示的是我們單元測(cè)試的結(jié)果(如果它成功了,會(huì)打印出一個(gè)“.”)。我們可以看到我們的測(cè)試失敗了,以及導(dǎo)致失敗的那行代碼,還有任何引發(fā)的異常信息。
為什么要測(cè)試?
在我們繼續(xù)那個(gè)例子之前,要問個(gè)很重要的問題:“為什么測(cè)試對(duì)我來(lái)說(shuō)有價(jià)值”?這是個(gè)公平的問題,也是那些對(duì)于代碼測(cè)試不熟悉的人常問的問題。畢竟,測(cè)試需要一定的時(shí)間,而我們完全可以用這些時(shí)間去編代碼,為什么要測(cè)試而不是去做那些最有生產(chǎn)效率的事?
有很多答案可以有效的回答這個(gè)問題,我列出了以下幾點(diǎn):
測(cè)試可以保證你的代碼在一系列給定條件下正常工作
測(cè)試確保了一系列條件下的正確性。語(yǔ)法錯(cuò)誤基本上一定通過測(cè)試被查出來(lái),一個(gè)代碼單元的基本的邏輯也可以通過測(cè)試被檢測(cè)出來(lái),以確保一定條件下的正確性。再次,它不是要證明代碼是在任何條件下都正確的。我們只是簡(jiǎn)單的瞄準(zhǔn)了一套比較完整的可能的條件(例如,你可以寫一個(gè)測(cè)試來(lái)監(jiān)測(cè)當(dāng)你調(diào)用my_addition_function(3, 'refrigerator), 的時(shí)候,但你不必為每個(gè)參數(shù)檢測(cè)所有可能的字符串)
測(cè)試允許人們確保對(duì)代碼的改動(dòng)不會(huì)破壞現(xiàn)有的功能
重構(gòu)代碼時(shí),這一點(diǎn)特別有用。如果沒有測(cè)試到位,你就沒法保證你的代碼的改變沒有破壞之前工作正常的東西。如果你希望更改或重寫你的代碼,并希望不會(huì)破壞任何東西,適當(dāng)?shù)膯卧獪y(cè)試是很必要的。
測(cè)試迫使人們?cè)诓粚こl件的情況下思考代碼,這可能會(huì)揭示出邏輯錯(cuò)誤
編寫測(cè)試強(qiáng)迫你去思考在非正常條件下你的代碼可能遇到的問題。在上面的例子中,my_addition_function函數(shù)可以將兩個(gè)數(shù)字相加。測(cè)試基本正確性的簡(jiǎn)單測(cè)試將調(diào)用my_addition_function(2,2),并斷言說(shuō)結(jié)果是4。然而,進(jìn)一步的測(cè)試可能會(huì)通過調(diào)用my_addition_function(2.0,2.0)來(lái)測(cè)試該功能是否能正確進(jìn)行浮點(diǎn)數(shù)的運(yùn)算。防御性的編碼原則表明你的代碼應(yīng)該能夠在非法輸入的情況下正常失效,因此測(cè)試時(shí),當(dāng)字符串類型被作為參數(shù)傳遞到函數(shù)中時(shí)應(yīng)當(dāng)拋出一個(gè)異常。
良好的測(cè)試要求模塊化,解耦代碼,這是一個(gè)良好的系統(tǒng)設(shè)計(jì)的標(biāo)志
單元測(cè)試的整體做法是通過代碼的松散耦合使其變得更容易。如果你的應(yīng)用程序代碼直接調(diào)用數(shù)據(jù)庫(kù),例如,測(cè)試你應(yīng)用程序的邏輯依賴于一個(gè)有效的數(shù)據(jù)庫(kù)連接,并且測(cè)試數(shù)據(jù)要存在于數(shù)據(jù)庫(kù)中。另一方面,隔離了外部資源的代碼在測(cè)試過程中更容易被模擬對(duì)象所替代。出于必要,(人們)設(shè)計(jì)的有測(cè)試能力的應(yīng)用程序最終采用了模塊化和松散耦合。
單元測(cè)試的剖析
通過繼續(xù)之前的例子,我們將看到如何編寫并組織單元測(cè)試?;叵胍幌?,primes.py包含以下代碼:
def is_prime(number): """Return True if *number* is prime.""" for element in range(number): if number % element == 0: return False return True def print_next_prime(number): """Print the closest prime number larger than *number*.""" index = number while True: index += 1 if is_prime(index): print(index)
同時(shí),文件test_primes.py包含如下代碼:
import unittest from primes import is_prime class PrimesTestCase(unittest.TestCase): """Tests for `primes.py`.""" def test_is_five_prime(self): """Is five successfully determined to be prime?""" self.assertTrue(is_prime(5)) if __name__ == '__main__': unittest.main()
做出斷言
unittest是Python標(biāo)準(zhǔn)庫(kù)中的一部分,并且也是我們開始“單元測(cè)試之旅”的一個(gè)好的起點(diǎn)。一個(gè)單元測(cè)試中包括一個(gè)或多個(gè)斷言(一些聲明被測(cè)試代碼的一些屬性為真的語(yǔ)句)。會(huì)想你上學(xué)的時(shí)候“斷言”這個(gè)詞的字面意思就是“陳述事實(shí)”。在單元測(cè)試中,斷言也是同樣的作用。
self.assertTrue 更像是自我解釋。它能聲明傳遞過去的參數(shù)的計(jì)算結(jié)果為真。unittest.TestCase類包含了許多斷言方法,所以一定要檢查列表并選擇合適的方法進(jìn)行測(cè)試。如果在每個(gè)測(cè)試中都用到assertTrue的話,則應(yīng)該考慮一個(gè)反模式,因?yàn)樗黾恿藴y(cè)試中讀者的認(rèn)知負(fù)擔(dān)。正確使用斷言的方法應(yīng)當(dāng)是使測(cè)試能夠明確說(shuō)明究竟是什么在被斷言(例如,很明顯?,只需掃一眼assertIsInstance 的方法名,就知道它要說(shuō)明的是其參數(shù))。
每個(gè)測(cè)試應(yīng)該測(cè)試一個(gè)單獨(dú)、有具體特性的代碼,并且應(yīng)該被賦予相關(guān)的命名。就單元測(cè)試發(fā)現(xiàn)機(jī)制的研究表明(主要在Python2.7+和3.2+版本中),測(cè)試方法應(yīng)該以test_為前綴命名。(這是可配置的,但是其目的是鑒別測(cè)試方法和非測(cè)試的實(shí)用方法)。如果我們把test_is_five_prime 的命名改為is_five_prime的話,運(yùn)行python中的test_primes.py時(shí)會(huì)輸出如下信息:
$ python test_primes.py ---------------------------------------------------------------------- Ran 0 tests in 0.000s OK
不要被上面信息中的“OK”所糊弄了,只有當(dāng)什么測(cè)試都沒真正運(yùn)行的時(shí)候才會(huì)顯示出“OK”!我認(rèn)為一個(gè)測(cè)試也沒跑其實(shí)應(yīng)該顯示個(gè)報(bào)錯(cuò)的,但是個(gè)人感覺放在一邊,這是一個(gè)你應(yīng)該注意是行為,尤其是當(dāng)通過程序運(yùn)行來(lái)檢查測(cè)試結(jié)果的時(shí)候(例如,一個(gè)持續(xù)的集成工具,像TracisCI)。
異常
讓我們回到test_primes.py的實(shí)際內(nèi)容中去,回憶一下運(yùn)行python test_primes.py指令后的輸出結(jié)果:
$ python test_primes.py E ====================================================================== ERROR: test_is_five_prime (__main__.PrimesTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_primes.py", line 8, in test_is_five_prime self.assertTrue(is_prime(5)) File "/home/jknupp/code/github_code/blug_private/primes.py", line 4, in is_prime if number % element == 0: ZeroDivisionError: integer division or modulo by zero ---------------------------------------------------------------------- Ran 1 test in 0.000s
這些輸出告訴我們,我們一個(gè)測(cè)試的結(jié)果失敗并不是因?yàn)橐粋€(gè)斷言失敗了,而是因?yàn)槌霈F(xiàn)了一個(gè)未捕獲的異常。事實(shí)上,由于拋出了一個(gè)異常,unittest框架并沒有能夠運(yùn)行我們的測(cè)試就返回了。
這里的問題很明確:我們使用的求模運(yùn)算的計(jì)算范圍中包括了0,因此執(zhí)行了一個(gè)除以0的操作。為了解決這個(gè)問題,我們可以很簡(jiǎn)單的將起始值由0變?yōu)?,并指出對(duì)0求模是錯(cuò)誤的,而對(duì)1求模則一直是真(并且一個(gè)素?cái)?shù)只能被自身和1整除,因此我們無(wú)需檢查1)。
解決問題
一次失敗的測(cè)試使我們修改了代碼。一旦我們改好了這個(gè)錯(cuò)誤(將s_prime中的一行改為for element in range(2, number):),我們就得到了如下輸出:
$ python test_primes.py . ---------------------------------------------------------------------- Ran 1 test in 0.000s
現(xiàn)在錯(cuò)誤已經(jīng)改了,這是不是意味著我們應(yīng)該刪掉test_is_five_prime這個(gè)測(cè)試方法(因?yàn)楹苊黠@,它將不會(huì)一直能通過測(cè)試)?不應(yīng)該刪。由于通過測(cè)試是最終目標(biāo)的話單元測(cè)試應(yīng)該盡量少的被刪除。我們已經(jīng)測(cè)試過is_prime的語(yǔ)法是有效的,并且,至少在一種情況下,它返回正確的結(jié)果。我們的目標(biāo)是要建立一套能全部通過的(單元測(cè)試的邏輯分組)測(cè)試,雖然有些一開始可能會(huì)失敗。
test_is_five_prime用于處理一個(gè)“非特殊”的素?cái)?shù)。讓我們確保它也能正確處理非素?cái)?shù)。將以下方法添加到PrimesTestCase類:
def test_is_four_non_prime(self): """Is four correctly determined not to be prime?""" self.assertFalse(is_prime(4), msg='Four is not prime!')
請(qǐng)注意,這時(shí)我們給assert調(diào)用添加了可選的msg參數(shù)。如果該測(cè)試失敗了,我們的信息將被打印到控制臺(tái),并給運(yùn)行測(cè)試的人提供額外的信息。
邊界情況
我們已經(jīng)成功的測(cè)試了兩種普通情況?,F(xiàn)在讓我們考慮邊界情況下、或者那些不尋?;蛞馔獾妮斎氲挠美.?dāng)測(cè)試一個(gè)其范圍是正整數(shù)的函數(shù)時(shí),邊界情況下的實(shí)例包括0、1、負(fù)數(shù)和一個(gè)很大的數(shù)字?,F(xiàn)在讓我們來(lái)測(cè)試其中的一些。
添加一個(gè)對(duì)0的測(cè)試很簡(jiǎn)單。我們預(yù)計(jì)?is_prime(0)返回的是false,因?yàn)椋鶕?jù)定義,素?cái)?shù)必須大于1。
def test_is_zero_not_prime(self): """Is zero correctly determined not to be prime?""" self.assertFalse(is_prime(0))
可惜呀,輸出是:
python test_primes.py ..F ====================================================================== FAIL: test_is_zero_not_prime (__main__.PrimesTestCase) Is zero correctly determined not to be prime? ---------------------------------------------------------------------- Traceback (most recent call last): File "test_primes.py", line 17, in test_is_zero_not_prime self.assertFalse(is_prime(0)) AssertionError: True is not false ---------------------------------------------------------------------- Ran 3 tests in 0.000s FAILED (failures=1)
0被錯(cuò)誤的判定為素?cái)?shù)。我們忘記了,我們決定在數(shù)字范圍中跳過0和1。讓我們?cè)黾右粋€(gè)對(duì)他們的特殊檢查。
def is_prime(number): """Return True if *number* is prime.""" if number in (0, 1): return False for element in range(2, number): if number % element == 0: return False return True
現(xiàn)在測(cè)試通過了。我們的函數(shù)應(yīng)該怎樣處理一個(gè)負(fù)數(shù)?在寫這個(gè)測(cè)試用例之前就知道輸出結(jié)果是很重要的。在這種情況下,任何負(fù)數(shù)都應(yīng)該返回false。
def test_negative_number(self): """Is a negative number correctly determined not to be prime?""" for index in range(-1, -10, -1): self.assertFalse(is_prime(index))
這里我們覺得檢查從-1到-9的所有數(shù)字。在一個(gè)循環(huán)中調(diào)用test方法是非常合法的,在一個(gè)測(cè)試中多次調(diào)用斷言方法也可以。我們可以在下面用(更詳細(xì))的方式改寫代碼。
def test_negative_number(self): """Is a negative number correctly determined not to be prime?""" self.assertFalse(is_prime(-1)) self.assertFalse(is_prime(-2)) self.assertFalse(is_prime(-3)) self.assertFalse(is_prime(-4)) self.assertFalse(is_prime(-5)) self.assertFalse(is_prime(-6)) self.assertFalse(is_prime(-7)) self.assertFalse(is_prime(-8)) self.assertFalse(is_prime(-9))
這兩個(gè)是完全等價(jià)的。除了當(dāng)我們運(yùn)行循環(huán)版本時(shí),我們得到了一個(gè)我們不太想要的信息:
python test_primes.py ...F ====================================================================== FAIL: test_negative_number (__main__.PrimesTestCase) Is a negative number correctly determined not to be prime? ---------------------------------------------------------------------- Traceback (most recent call last): File "test_primes.py", line 22, in test_negative_number self.assertFalse(is_prime(index)) AssertionError: True is not false ---------------------------------------------------------------------- Ran 4 tests in 0.000s FAILED (failures=1)
嗯···我們知道測(cè)試失敗了,但是是在哪個(gè)負(fù)數(shù)上失敗的?非常沒用的是,Python的單元測(cè)試框架并沒有打印出預(yù)期值和實(shí)際值。我們可以移步到兩種方式上,并用其中之一來(lái)解決問題:通過msg參數(shù),或通過使用一個(gè)第三方的單元測(cè)試框架。
使用msg參數(shù)來(lái)assertFalse僅僅能夠使我們認(rèn)識(shí)到我們可以用字符串的格式設(shè)置來(lái)解決問題。
def test_negative_number(self): """Is a negative number correctly determined not to be prime?""" for index in range(-1, -10, -1): self.assertFalse(is_prime(index), msg='{} should not be determined to be prime'.format(index))
從而給出了如下輸出信息:
python test_primes ...F ====================================================================== FAIL: test_negative_number (test_primes.PrimesTestCase) Is a negative number correctly determined not to be prime? ---------------------------------------------------------------------- Traceback (most recent call last): File "./test_primes.py", line 22, in test_negative_number self.assertFalse(is_prime(index), msg='{} should not be determined to be prime'.format(index)) AssertionError: True is not false : -1 should not be determined to be prime ---------------------------------------------------------------------- Ran 4 tests in 0.000s FAILED (failures=1)
妥善地修復(fù)代碼
我們看到,失敗的負(fù)數(shù)是第一個(gè)數(shù)字:-1。為了解決這個(gè)問題,我們可以為負(fù)數(shù)增再增加一個(gè)特殊檢查,但是編寫單元測(cè)試的目的不是盲目的添加代碼來(lái)檢測(cè)邊界情況。當(dāng)一個(gè)測(cè)試失敗時(shí),我們應(yīng)該退后一步并且確定解決問題的最佳方式。在這種情況下,我們就不該增加一個(gè)額外的if:
def is_prime(number): """Return True if *number* is prime.""" if number < 0: return False if number in (0, 1): return False for element in range(2, number): if number % element == 0: return False return True
應(yīng)當(dāng)首先使用如下代碼:
def is_prime(number): """Return True if *number* is prime.""" if number <= 1: return False for element in range(2, number): if number % element == 0: return False return True
在后一個(gè)代碼中,我們發(fā)現(xiàn)如果參數(shù)小于等于1時(shí),兩個(gè)if語(yǔ)句可以合并到一個(gè)返回值為false的語(yǔ)句中。這樣做不僅更加簡(jiǎn)潔,并且很好的貼合了素?cái)?shù)的定義(一個(gè)比1大并且只能被1和它本身整除的數(shù))。
第三方測(cè)試框架
我們本來(lái)也可以通過使用第三方測(cè)試框架解決這個(gè)由于信息太少導(dǎo)致測(cè)試失敗的問題。最常用的兩個(gè)是py.test和nose。通過運(yùn)行語(yǔ)句py.test -l(-l為顯示局部變量的值)可以得到如下結(jié)果。
#! bash py.test -l test_primes.py ============================= test session starts ============================== platform linux2 -- Python 2.7.6 -- pytest-2.4.2 collected 4 items test_primes.py ...F =================================== FAILURES =================================== _____________________ PrimesTestCase.test_negative_number ______________________ self = <test_primes.PrimesTestCase testMethod=test_negative_number> def test_negative_number(self): """Is a negative number correctly determined not to be prime?""" for index in range(-1, -10, -1): > self.assertFalse(is_prime(index)) E AssertionError: True is not false index = -1 self = <test_primes.PrimesTestCase testMethod=test_negative_number> test_primes.py:22: AssertionError
正如你所看到的,一些更有用的信息。這些框架提供了比單純的更詳細(xì)的輸出更多的功能,但問題是僅僅知道它們能存在和擴(kuò)展內(nèi)置unittest測(cè)試包的功能。
結(jié)束語(yǔ)
在這篇文章中,你學(xué)到了什么是單元測(cè)試,為什么它們?nèi)绱酥匾?,還有怎樣編寫測(cè)試。這就是說(shuō),要注意我們只是剖開了測(cè)試方法學(xué)中的表層,更多高級(jí)的話題,比如測(cè)試案例的組織、持續(xù)整合以及測(cè)試案例的管理等都是可供那些想要進(jìn)一步學(xué)習(xí)Python中的測(cè)試的讀者研究的很好的話題。
- 在不改變其功能的前提下重組/清理代碼
- 編代碼時(shí)不暴露其內(nèi)部數(shù)據(jù)或函數(shù)并且不使用其他代碼的內(nèi)部數(shù)據(jù)或函數(shù)
相關(guān)文章
從零學(xué)Python之入門(二)基本數(shù)據(jù)類型
這是繼“hello world”之后的第二篇入門級(jí)基礎(chǔ)知識(shí),以后這個(gè)系列會(huì)按照入門、進(jìn)階、精通三個(gè)分類進(jìn)行下去,歡迎高手們來(lái)拍磚2014-05-05python 字典 按key值大小 倒序取值的實(shí)例
今天小編就為大家分享一篇python 字典 按key值大小 倒序取值的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2018-07-07python?包(模塊?函數(shù)?類?定義?導(dǎo)入)使用詳解
這篇文章主要為大家介紹了python?包(模塊?函數(shù)?類?定義?導(dǎo)入)的使用詳細(xì)講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03Python+OpenCV 實(shí)現(xiàn)圖片無(wú)損旋轉(zhuǎn)90°且無(wú)黑邊
今天小編就為大家分享一篇Python+OpenCV 實(shí)現(xiàn)圖片無(wú)損旋轉(zhuǎn)90°且無(wú)黑邊,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2019-12-12Python 工具類實(shí)現(xiàn)大文件斷點(diǎn)續(xù)傳功能詳解
用python進(jìn)行大文件下載的時(shí)候,一旦出現(xiàn)網(wǎng)絡(luò)波動(dòng)問題,導(dǎo)致文件下載到一半。如果將下載不完全的文件刪掉,那么又需要從頭開始,如果連續(xù)網(wǎng)絡(luò)波動(dòng),是不是要頭禿了。本文提供斷點(diǎn)續(xù)傳下載工具方法,希望可以幫助到你2021-10-10pytorch中backward()方法如何自動(dòng)求梯度
這篇文章主要介紹了pytorch中backward()方法如何自動(dòng)求梯度問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02Python如何實(shí)現(xiàn)轉(zhuǎn)換URL詳解
這篇文章主要介紹了Python如何實(shí)現(xiàn)轉(zhuǎn)換URL詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07