新聞中心
Python已經(jīng)演化出了一個(gè)廣泛的生態(tài)系統(tǒng),該生態(tài)系統(tǒng)能夠讓Python程序員的生活變得更加簡(jiǎn)單,減少他們重復(fù)造輪的工作。同樣的理念也適用于工具開(kāi)發(fā)者的工作,即便他們開(kāi)發(fā)出的工具并沒(méi)有出現(xiàn)在最終的程序中。本文將介紹Python程序員必知必會(huì)的開(kāi)發(fā)者工具。

對(duì)于開(kāi)發(fā)者來(lái)說(shuō),最實(shí)用的幫助莫過(guò)于幫助他們編寫(xiě)代碼文檔了。pydoc模塊可以根據(jù)源代碼中的docstrings為任何可導(dǎo)入模塊生成格式良好的文檔。Python包含了兩個(gè)測(cè)試框架來(lái)自動(dòng)測(cè)試代碼以及驗(yàn)證代碼的正確性:1)doctest模塊,該模塊可以從源代碼或獨(dú)立文件的例子中抽取出測(cè)試用例。2)unittest模塊,該模塊是一個(gè)全功能的自動(dòng)化測(cè)試框架,該框架提供了對(duì)測(cè)試準(zhǔn)備(test fixtures), 預(yù)定義測(cè)試集(predefined test suite)以及測(cè)試發(fā)現(xiàn)(test discovery)的支持。
trace模 塊可以監(jiān)控Python執(zhí)行程序的方式,同時(shí)生成一個(gè)報(bào)表來(lái)顯示程序的每一行執(zhí)行的次數(shù)。這些信息可以用來(lái)發(fā)現(xiàn)未被自動(dòng)化測(cè)試集所覆蓋的程序執(zhí)行路徑,也 可以用來(lái)研究程序調(diào)用圖,進(jìn)而發(fā)現(xiàn)模塊之間的依賴(lài)關(guān)系。編寫(xiě)并執(zhí)行測(cè)試可以發(fā)現(xiàn)絕大多數(shù)程序中的問(wèn)題,Python使得debug工作變得更加簡(jiǎn)單,這是 因?yàn)樵诖蟛糠智闆r下,Python都能夠?qū)⑽幢惶幚淼腻e(cuò)誤打印到控制臺(tái)中,我們稱(chēng)這些錯(cuò)誤信息為traceback。如果程序不是在文本控制臺(tái)中運(yùn)行 的,traceback也能夠?qū)㈠e(cuò)誤信息輸出到日志文件或是消息對(duì)話框中。當(dāng)標(biāo)準(zhǔn)的traceback無(wú)法提供足夠的信息時(shí),可以使用cgitb 模塊來(lái)查看各級(jí)棧和源代碼上下文中的詳細(xì)信息,比如局部變量。cgitb模塊還能夠?qū)⑦@些跟蹤信息以HTML的形式輸出,用來(lái)報(bào)告web應(yīng)用中的錯(cuò)誤。
一旦發(fā)現(xiàn)了問(wèn)題出在哪里后,就需要使用到交互式調(diào)試器進(jìn)入到代碼中進(jìn)行調(diào)試工作了,pdb模塊能夠很好地勝任這項(xiàng)工作。該模塊可以顯示出程序在錯(cuò)誤產(chǎn)生時(shí)的執(zhí)行路徑,同時(shí)可以動(dòng)態(tài)地調(diào)整對(duì)象和代碼進(jìn)行調(diào)試。當(dāng)程序通過(guò)測(cè)試并調(diào)試后,下一步就是要將注意力放到性能上了。開(kāi)發(fā)者可以使用profile以及timit模塊來(lái)測(cè)試程序的速度,找出程序中到底是哪里很慢,進(jìn)而對(duì)這部分代碼獨(dú)立出來(lái)進(jìn)行調(diào)優(yōu)的工作。Python程序是通過(guò)解釋器執(zhí)行的,解釋器的輸入是原有程序的字節(jié)碼編譯版本。這個(gè)字節(jié)碼編譯版本可以在程序執(zhí)行時(shí)動(dòng)態(tài)地生成,也可以在程序打包的時(shí)候就生成。compileall模塊可以處理程序打包的事宜,它暴露出了打包相關(guān)的接口,該接口能夠被安裝程序和打包工具用來(lái)生成包含模塊字節(jié)碼的文件。同時(shí),在開(kāi)發(fā)環(huán)境中,compileall模塊也可以用來(lái)驗(yàn)證源文件是否包含了語(yǔ)法錯(cuò)誤。
在源代碼級(jí)別,pyclbr模塊提供了一個(gè)類(lèi)查看器,方便文本編輯器或是其他程序?qū)ython程序中有意思的字符進(jìn)行掃描,比如函數(shù)或者是類(lèi)。在提供了類(lèi)查看器以后,就無(wú)需引入代碼,這樣就避免了潛在的副作用影響。
文檔字符串與doctest模塊
如果函數(shù),類(lèi)或者是模塊的***行是一個(gè)字符串,那么這個(gè)字符串就是一個(gè)文檔字符串??梢哉J(rèn)為包含文檔字符串是一個(gè)良好的編程習(xí)慣,這是因?yàn)檫@些字符串可以給Python程序開(kāi)發(fā)工具提供一些信息。比如,help()命令能夠檢測(cè)文檔字符串,Python相關(guān)的IDE也能夠進(jìn)行檢測(cè)文檔字符串的工作。由于程序員傾向于在交互式shell中查看文檔字符串,所以***將這些字符串寫(xiě)的簡(jiǎn)短一些。例如
- # mult.py
- class Test:
- """
- >>> a=Test(5)
- >>> a.multiply_by_2()
- 10
- """
- def __init__(self, number):
- self._number=number
- def multiply_by_2(self):
- return self._number*2
在編寫(xiě)文檔時(shí),一個(gè)常見(jiàn)的問(wèn)題就是如何保持文檔和實(shí)際代碼的同步。例如,程序員也許會(huì)修改函數(shù)的實(shí)現(xiàn),但是卻忘記了更新文檔。針對(duì)這個(gè)問(wèn)題,我們可以使用 doctest模塊。doctest模塊收集文檔字符串,并對(duì)它們進(jìn)行掃描,然后將它們作為測(cè)試進(jìn)行執(zhí)行。為了使用doctest模塊,我們通常會(huì)新建一 個(gè)用于測(cè)試的獨(dú)立的模塊。例如,如果前面的例子Test class包含在文件mult.py中,那么,你應(yīng)該新建一個(gè)testmult.py文件用來(lái)測(cè)試,如下所示:
- # testmult.py
- import mult, doctest
- doctest.testmod(mult, verbose=True)
- # Trying:
- # a=Test(5)
- # Expecting nothing
- # ok
- # Trying:
- # a.multiply_by_2()
- # Expecting:
- # 10
- # ok
- # 3 items had no tests:
- # mult
- # mult.Test.__init__
- # mult.Test.multiply_by_2
- # 1 items passed all tests:
- # 2 tests in mult.Test
- # 2 tests in 4 items.
- # 2 passed and 0 failed.
- # Test passed.
在這段代碼中,doctest.testmod(module)會(huì)執(zhí)行特定模塊的測(cè)試,并且返回測(cè)試失敗的個(gè)數(shù)以及測(cè)試的總數(shù)目。如果所有的測(cè)試都通過(guò)了,那么不會(huì)產(chǎn)生任何輸出。否則的話,你將會(huì)看到一個(gè)失敗報(bào)告,用來(lái)顯示期望值和實(shí)際值之間的差別。如果你想看到測(cè)試的詳細(xì)輸出,你可以使用testmod(module, verbose=True).
如果不想新建一個(gè)單獨(dú)的測(cè)試文件的話,那么另一種選擇就是在文件末尾包含相應(yīng)的測(cè)試代碼:
- if __name__ == '__main__':
- import doctest
- doctest.testmod()
如果想執(zhí)行這類(lèi)測(cè)試的話,我們可以通過(guò)-m選項(xiàng)調(diào)用doctest模塊。通常來(lái)講,當(dāng)執(zhí)行測(cè)試的時(shí)候沒(méi)有任何的輸出。如果想查看詳細(xì)信息的話,可以加上-v選項(xiàng)。
- $ python -m doctest -v mult.py
單元測(cè)試與unittest模塊
如果想更加徹底地 對(duì)程序進(jìn)行測(cè)試,我們可以使用unittest模塊。通過(guò)單元測(cè)試,開(kāi)發(fā)者可以為構(gòu)成程序的每一個(gè)元素(例如,獨(dú)立的函數(shù),方法,類(lèi)以及模塊)編寫(xiě)一系列 獨(dú)立的測(cè)試用例。當(dāng)測(cè)試更大的程序時(shí),這些測(cè)試就可以作為基石來(lái)驗(yàn)證程序的正確性。當(dāng)我們的程序變得越來(lái)越大的時(shí)候,對(duì)不同構(gòu)件的單元測(cè)試就可以組合起來(lái) 成為更大的測(cè)試框架以及測(cè)試工具。這能夠極大地簡(jiǎn)化軟件測(cè)試的工作,為找到并解決軟件問(wèn)題提供了便利。
- # splitter.py
- import unittest
- def split(line, types=None, delimiter=None):
- """Splits a line of text and optionally performs type conversion.
- ...
- """
- fields = line.split(delimiter)
- if types:
- fields = [ ty(val) for ty,val in zip(types,fields) ]
- return fields
- class TestSplitFunction(unittest.TestCase):
- def setUp(self):
- # Perform set up actions (if any)
- pass
- def tearDown(self):
- # Perform clean-up actions (if any)
- pass
- def testsimplestring(self):
- r = split('GOOG 100 490.50')
- self.assertEqual(r,['GOOG','100','490.50'])
- def testtypeconvert(self):
- r = split('GOOG 100 490.50',[str, int, float])
- self.assertEqual(r,['GOOG', 100, 490.5])
- def testdelimiter(self):
- r = split('GOOG,100,490.50',delimiter=',')
- self.assertEqual(r,['GOOG','100','490.50'])
- # Run the unittests
- if __name__ == '__main__':
- unittest.main()
- #...
- #----------------------------------------------------------------------
- #Ran 3 tests in 0.001s
- #OK
在使用單元測(cè)試時(shí),我們需要定義一個(gè)繼承自u(píng)nittest.TestCase的類(lèi)。在這個(gè)類(lèi)里面,每一個(gè)測(cè)試都以方法的形式進(jìn)行定義,并都以test打頭進(jìn)行命名——例如,’testsimplestring‘,’testtypeconvert‘以及類(lèi)似的命名方式(有必要強(qiáng)調(diào)一下,只要方法名以test打頭,那么無(wú)論怎么命名都是可以的)。在每個(gè)測(cè)試中,斷言可以用來(lái)對(duì)不同的條件進(jìn)行檢查。
實(shí)際的例子:
假如你在程序里有一個(gè)方法,這個(gè)方法的輸出指向標(biāo)準(zhǔn)輸出(sys.stdout)。這通常意味著是往屏幕上輸出文本信息。如果你想對(duì)你的代碼進(jìn)行測(cè)試來(lái)證明這一點(diǎn),只要給出相應(yīng)的輸入,那么對(duì)應(yīng)的輸出就會(huì)被顯示出來(lái)。
- # url.py
- def urlprint(protocol, host, domain):
- url = '{}://{}.{}'.format(protocol, host, domain)
- print(url)
內(nèi)置的print函數(shù)在默認(rèn)情況下會(huì)往sys.stdout發(fā)送輸出。為了測(cè)試輸出已經(jīng)實(shí)際到達(dá),你可以使用一個(gè)替身對(duì)象對(duì)其進(jìn)行模擬,并且對(duì)程序的期望值進(jìn)行斷言。unittest.mock模塊中的patch()方法可以只在運(yùn)行測(cè)試的上下文中才替換對(duì)象,在測(cè)試完成后就立刻返回對(duì)象原始的狀態(tài)。下面是urlprint()方法的測(cè)試代碼:
- #urltest.py
- from io import StringIO
- from unittest import TestCase
- from unittest.mock import patch
- import url
- class TestURLPrint(TestCase):
- def test_url_gets_to_stdout(self):
- protocol = 'http'
- host = 'www'
- domain = 'example.com'
- expected_url = '{}://{}.{}\n'.format(protocol, host, domain)
- with patch('sys.stdout', new=StringIO()) as fake_out:
- url.urlprint(protocol, host, domain)
- self.assertEqual(fake_out.getvalue(), expected_url)
urlprint()函數(shù)有三個(gè)參數(shù),測(cè)試代碼首先給每個(gè)參數(shù)賦了一個(gè)假值。變量expected_url包含了期望的輸出字符串。為了能夠執(zhí)行測(cè)試,我們使用了unittest.mock.patch()方法作為上下文管理器,把標(biāo)準(zhǔn)輸出sys.stdout替換為了StringIO對(duì)象,這樣發(fā)送的標(biāo)準(zhǔn)輸出的內(nèi)容就會(huì)被StringIO對(duì)象所接收。變量fake_out就是在這一過(guò)程中所創(chuàng)建出的模擬對(duì)象,該對(duì)象能夠在with所處的代碼塊中所使用,來(lái)進(jìn)行一系列的測(cè)試檢查。當(dāng)with語(yǔ) 句完成時(shí),patch方法能夠?qū)⑺械臇|西都復(fù)原到測(cè)試執(zhí)行之前的狀態(tài),就好像測(cè)試沒(méi)有執(zhí)行一樣,而這無(wú)需任何額外的工作。但對(duì)于某些Python的C擴(kuò) 展來(lái)講,這個(gè)例子卻顯得毫無(wú)意義,這是因?yàn)檫@些C擴(kuò)展程序繞過(guò)了sys.stdout的設(shè)置,直接將輸出發(fā)送到了標(biāo)準(zhǔn)輸出上。這個(gè)例子僅適用于純 Python代碼的程序(如果你想捕獲到類(lèi)似C擴(kuò)展的輸入輸出,那么你可以通過(guò)打開(kāi)一個(gè)臨時(shí)文件然后將標(biāo)準(zhǔn)輸出重定向到該文件的技巧來(lái)進(jìn)行實(shí)現(xiàn))。
Python調(diào)試器與pdb模塊
Python在 pdb模塊中包含了一個(gè)簡(jiǎn)單的基于命令行的調(diào)試器。pdb模塊支持事后調(diào)試(post-mortem debugging),棧幀探查(inspection of stack frames),斷點(diǎn)(breakpoints),單步調(diào)試(single-stepping of source lines)以及代碼審查(code evaluation)。
有好幾個(gè)函數(shù)都能夠在程序中調(diào)用調(diào)試器,或是在交互式的Python終端中進(jìn)行調(diào)試工作。
在所有啟動(dòng)調(diào)試器的函數(shù)中,函數(shù)set_trace()也許是最簡(jiǎn)易實(shí)用的了。如果在復(fù)雜程序中發(fā)現(xiàn)了問(wèn)題,可以在代碼中插入set_trace()函數(shù),并運(yùn)行程序。當(dāng)執(zhí)行到set_trace()函數(shù)時(shí),這就會(huì)暫停程序的執(zhí)行并直接跳轉(zhuǎn)到調(diào)試器中,這時(shí)候你就可以大展手腳開(kāi)始檢查運(yùn)行時(shí)環(huán)境了。當(dāng)退出調(diào)試器時(shí),調(diào)試器會(huì)自動(dòng)恢復(fù)程序的執(zhí)行。
假設(shè)你的程序有問(wèn)題,你想找到一個(gè)簡(jiǎn)單的方法來(lái)對(duì)它進(jìn)行調(diào)試。
如果你的程序崩潰時(shí)報(bào)了一個(gè)異常錯(cuò)誤,那么你可以用python3 -i someprogram.py這個(gè)命令來(lái)運(yùn)行你的程序,這能夠很好地發(fā)現(xiàn)問(wèn)題所在。-i選項(xiàng)表明只要程序終結(jié)就立即啟動(dòng)一個(gè)交互式shell。在這個(gè)交互式shell中,你就可以很好地探查到底發(fā)生了什么導(dǎo)致程序的錯(cuò)誤。例如,如果你有以下代碼:
- def function(n):
- return n + 10
- function("Hello")
如果使用python3 -i 命令運(yùn)行程序就會(huì)產(chǎn)生如下輸出:
- python3 -i sample.py
- Traceback (most recent call last):
- File "sample.py", line 4, in
- function("Hello")
- File "sample.py", line 2, in function
- return n + 10
- TypeError: Can't convert 'int' object to str implicitly
- >>> function(20)
- 30
- >>>
如果你沒(méi)有發(fā)現(xiàn)什么明顯的錯(cuò)誤,那么你可以進(jìn)一步地啟動(dòng)Python調(diào)試器。例如:
- >>> import pdb
- >>> pdb.pm()
- > sample.py(4)func()
- -> return n + 10
- (Pdb) w
- sample.py(6)
() - -> func('Hello')
- > sample.py(4)func()
- -> return n + 10
- (Pdb) print n
- 'Hello'
- (Pdb) q
- >>>
如果你的代碼身處的環(huán)境很難啟動(dòng)一個(gè)交互式shell的話(比如在服務(wù)器環(huán)境下),你可以增加錯(cuò)誤處理的代碼,并自己輸出跟蹤信息。例如:
- import traceback
- import sys
- try:
- func(arg)
- except:
- print('**** AN ERROR OCCURRED ****')
- traceback.print_exc(file=sys.stderr)
如果你的程序并沒(méi)有崩潰,而是說(shuō)程序的行為與你的預(yù)期表現(xiàn)的不一致,那么你可以嘗試在一些可能出錯(cuò)的地方加入print()函數(shù)。如果你打算采用這種方案 的話,那么還有些相關(guān)的技巧值得探究。首先,函數(shù)traceback.print_stack()能夠在被執(zhí)行時(shí)立即打印出程序中棧的跟蹤信息。例如:
- >>> def sample(n):
- ... if n > 0:
- ... sample(n-1)
- ... else:
- ... traceback.print_stack(file=sys.stderr)
- ...
- >>> sample(5)
- File "
", line 1, in - File "
", line 3, in sample - File "
", line 3, in sample - File "
", line 3, in sample - File "
", line 3, in sample - File "
", line 3, in sample - File "
", line 5, in sample - >>>
另外,你可以在程序中任意一處使用pdb.set_trace()手動(dòng)地啟動(dòng)調(diào)試器,就像這樣:
- import pdb
- def func(arg):
- ...
- pdb.set_trace()
- ...
深入解析大型程序的時(shí)候,這是一個(gè)非常實(shí)用的技巧,這樣操作能夠清楚地了解程序的控制流或是函數(shù)的參數(shù)。比如,一旦調(diào)試器啟動(dòng)了之后,你就可以使用print或者w命令來(lái)查看變量,來(lái)了解棧的跟蹤信息。
在進(jìn)行軟件調(diào)試時(shí),千萬(wàn)不要讓事情變得很復(fù)雜。有時(shí)候僅僅需要知道程序的跟蹤信息就能夠解決大部分的簡(jiǎn)單錯(cuò)誤(比如,實(shí)際的錯(cuò)誤總是顯示在跟蹤信息的***一行)。在實(shí)際的開(kāi)發(fā)過(guò)程中,將print()函數(shù)插入到代碼中也能夠很方便地顯示調(diào)試信息(只需要記得在調(diào)試完以后將print語(yǔ)句刪除掉就行了)。調(diào)試器的通用用法是在崩潰的函數(shù)中探查變量的值,知道如何在程序崩潰以后再進(jìn)入到調(diào)試器中就顯得非常實(shí)用。在程序的控制流不是那么清楚的情況下,你可以插入pdb.set_trace()語(yǔ)句來(lái)理清復(fù)雜程序的思路。本質(zhì)上,程序會(huì)一直執(zhí)行直到遇到set_trace()調(diào)用,之后程序就會(huì)立刻跳轉(zhuǎn)進(jìn)入到調(diào)試器中。在調(diào)試器里,你就可以進(jìn)行更多的嘗試。如果你正在使用Python的IDE,那么IDE通常會(huì)提供基于pdb的調(diào)試接口,你可以查閱IDE的相關(guān)文檔來(lái)獲取更多的信息。
下面是一些Python調(diào)試器入門(mén)的資源列表:
- 閱讀Steve Ferb的文章 “Debugging in Python”
- 觀看Eric Holscher的截圖 “Using pdb, the Python Debugger”
- 閱讀Ayman Hourieh的文章 “Python Debugging Techniques”
- 閱讀 Python documentation for pdb – The Python Debugger
- 閱讀Karen Tracey的D jango 1.1 Testing and Debugging一書(shū)中的第九章——When You Don’t Even Know What to Log: Using Debuggers
程序分析
profile模塊和cProfile模塊可以用來(lái)分析程序。它們的工作原理都一樣,唯一的區(qū)別是,cProfile模塊 是以C擴(kuò)展的方式實(shí)現(xiàn)的,如此一來(lái)運(yùn)行的速度也快了很多,也顯得比較流行。這兩個(gè)模塊都可以用來(lái)收集覆蓋信息(比如,有多少函數(shù)被執(zhí)行了),也能夠收集性 能數(shù)據(jù)。對(duì)一個(gè)程序進(jìn)行分析的最簡(jiǎn)單的方法就是運(yùn)行這個(gè)命令:
- % python -m cProfile someprogram.py
此外,也可以使用profile模塊中的run函數(shù):
- run(command [, filename])
該函數(shù)會(huì)使用exec語(yǔ)句執(zhí)行command中的內(nèi)容。filename是可選的文件保存名,如果沒(méi)有filename的話,該命令的輸出會(huì)直接發(fā)送到標(biāo)準(zhǔn)輸出上。
下面是分析器執(zhí)行完成時(shí)的輸出報(bào)告:
- 126 function calls (6 primitive calls) in 5.130 CPU seconds
- Ordered by: standard name
- ncalls tottime percall cumtime percall filename:lineno(function)
- 1 0.030 0.030 5.070 5.070
:1(?) - 121/1 5.020 0.041 5.020 5.020 book.py:11(process)
- 1 0.020 0.020 5.040 5.040 book.py:5(?)
- 2 0.000 0.000 0.000 0.000 exceptions.py:101(_ _init_ _)
- 1 0.060 0.060 5.130 5.130 profile:0(execfile('book.py'))
- 0 0.000 0.000 profile:0(profiler)
當(dāng)輸出中的***列包含了兩個(gè)數(shù)字時(shí)(比如,121/1),后者是元調(diào)用(primitive call)的次數(shù),前者是實(shí)際調(diào)用的次數(shù)(譯者注:只有在遞歸情況下,實(shí)際調(diào)用的次數(shù)才會(huì)大于元調(diào)用的次數(shù),其他情況下兩者都相等)。對(duì)于絕大部分的應(yīng)用 程序來(lái)講使用該模塊所產(chǎn)生的的分析報(bào)告就已經(jīng)足夠了,比如,你只是想簡(jiǎn)單地看一下你的程序花費(fèi)了多少時(shí)間。然后,如果你還想將這些數(shù)據(jù)保存下來(lái),并在將來(lái) 對(duì)其進(jìn)行分析,你可以使用pstats模塊。
假設(shè)你想知道你的程序究竟在哪里花費(fèi)了多少時(shí)間。
如果你只是想簡(jiǎn)單地給你的整個(gè)程序計(jì)時(shí)的話,使用Unix中的time命令就已經(jīng)完全能夠應(yīng)付了。例如:
- bash % time python3 someprogram.py
- real 0m13.937s
- user 0m12.162s
- sys 0m0.098s
- bash %
通常來(lái)講,分析代碼的程度會(huì)介于這兩個(gè)極端之間。比如,你可能已經(jīng)知道你的代碼會(huì)在一些特定的函數(shù)中花的時(shí)間特別多。針對(duì)這類(lèi)特定函數(shù)的分析,我們可以使用修飾器decorator,例如:
- import time
- from functools import wraps
- def timethis(func):
- @wraps(func)
- def wrapper(*args, **kwargs):
- start = time.perf_counter()
- r = func(*args, **kwargs)
- end = time.perf_counter()
- print('{}.{} : {}'.format(func.__module__, func.__name__, end - start))
- return r
- return wrapper
使用decorator的方式很簡(jiǎn)單,你只需要把它放在你想要分析的函數(shù)的定義前面就可以了。例如:
- >>> @timethis
- ... def countdown(n):
- ... while n > 0:
- ... n -= 1
- ...
- >>> countdown(10000000)
- __main__.countdown : 0.803001880645752
- >>>
如果想要分析一個(gè)語(yǔ)句塊的話,你可以定義一個(gè)上下文管理器(context manager)。例如:
- import time
- from contextlib import contextmanager
- @contextmanager
- def timeblock(label):
- start = time.perf_counter()
- try:
- yield
- finally:
- end = time.perf_counter()
- print('{} : {}'.format(label, end - start))
接下來(lái)是如何使用上下文管理器的例子:
- >>> with timeblock('counting'):
- ... n = 10000000
- ... while n > 0:
- ... n -= 1
- ...
- counting : 1.5551159381866455
- >>>
分享文章:Python程序員必知必會(huì)的開(kāi)發(fā)者工具
新聞來(lái)源:http://fisionsoft.com.cn/article/dhgdieg.html


咨詢(xún)
建站咨詢(xún)
