你是否對函數(shù)、類、方法、庫和模塊等花哨的編程術(shù)語感到困惑?你是否在與變量作用域斗爭?無論你是自學(xué)成才的還是經(jīng)過正式培訓(xùn)的程序員,代碼的模塊化都會令人困惑。但是類和庫鼓勵模塊化代碼,因為模塊化代碼意味著只需構(gòu)建一個多用途代碼塊集合,就可以在許多項目中使用它們來減少編碼工作量。換句話說,如果你按照本文對Python函數(shù)的研究,你將找到更聰明的工作方法,這意味著更少的工作。
本文假定你對Python很熟(LCTT譯注:稍微熟悉就可以),并且可以編寫和運行一個簡單的腳本。如果你還沒有使用過Python,請首先閱讀我的文章:Python簡介。
函數(shù)
函數(shù)是邁向模塊化過程中重要的一步,因為它們是形式化的重復(fù)方法。如果在你的程序中,有一個任務(wù)需要反復(fù)執(zhí)行,那么你可以將代碼放入一個函數(shù)中,根據(jù)需要隨時調(diào)用該函數(shù)。這樣,你只需編寫一次代碼,就可以隨意使用它。
以下一個簡單函數(shù)的示例:
#!/usr/bin/envpython3
importtime
defTimer():
print("Timeis"+str(time.time()))
創(chuàng)建一個名為mymodularity的目錄,并將以上函數(shù)代碼保存為該目錄下的timestamp.py。
除了這個函數(shù),在mymodularity目錄中創(chuàng)建一個名為__init__.py的文件,你可以在文件管理器或bashshell中執(zhí)行此操作:
$touchmymodularity/__init__.py
現(xiàn)在,你已經(jīng)創(chuàng)建了屬于你自己的Python庫(Python中稱為“模塊”),名為mymodularity。它不是一個特別有用的模塊,因為它所做的只是導(dǎo)入time模塊并打印一個時間戳,但這只是一個開始。
要使用你的函數(shù),像對待任何其他Python模塊一樣對待它。以下是一個小應(yīng)用,它使用你的mymodularity軟件包來測試Pythonsleep()函數(shù)的準(zhǔn)確性。將此文件保存為sleeptest.py,注意要在mymodularity文件夾之外,因為如果你將它保存在mymodularity里面,那么它將成為你的包中的一個模塊,你肯定不希望這樣。
#!/usr/bin/envpython3
importtime
frommymodularityimporttimestamp
print("TestingPythonsleep()...")
#modularity
timestamp.Timer()
time.sleep(3)
timestamp.Timer()
在這個簡單的腳本中,你從mymodularity包中調(diào)用timestamp模塊兩次。從包中導(dǎo)入模塊時,通常的語法是從包中導(dǎo)入你所需的模塊,然后使用模塊名稱+一個點+要調(diào)用的函數(shù)名(例如timestamp.Timer())。
你調(diào)用了兩次Timer()函數(shù),所以如果你的timestamp模塊比這個簡單的例子復(fù)雜些,那么你將節(jié)省大量重復(fù)代碼。
保存文件并運行:
$python3./sleeptest.py
TestingPythonsleep()...
Timeis1560711266.1526039
Timeis1560711269.1557732
根據(jù)測試,Python中的sleep函數(shù)非常準(zhǔn)確:在三秒鐘等待之后,時間戳成功且正確地增加了3,在微秒單位上差距很小。
Python庫的結(jié)構(gòu)看起來可能令人困惑,但其實它并不是什么魔法。Python被編程為一個包含Python代碼的目錄,并附帶一個__init__.py文件,那么這個目錄就會被當(dāng)作一個包,并且Python會首先在當(dāng)前目錄中查找可用模塊。這就是為什么語句frommymodularityimporttimestamp有效的原因:Python在當(dāng)前目錄查找名為mymodularity的目錄,然后查找timestamp.py文件。
你在這個例子中所做的功能和以下這個非模塊化的版本是一樣的:
#!/usr/bin/envpython3
importtime
frommymodularityimporttimestamp
print("TestingPythonsleep()...")
#nomodularity
print("Timeis"+str(time.time()))
time.sleep(3)
print("Timeis"+str(time.time()))
對于這樣一個簡單的例子,其實沒有必要以這種方式編寫測試,但是對于編寫自己的模塊來說,優(yōu)秀的實踐是你的代碼是通用的,可以將它重用于其他項目。
通過在調(diào)用函數(shù)時傳遞信息,可以使代碼更通用。例如,假設(shè)你想要使用模塊來測試的不是系統(tǒng)的sleep函數(shù),而是用戶自己實現(xiàn)的sleep函數(shù),更改timestamp代碼,使它接受一個名為msg的傳入變量,它將是一個字符串,控制每次調(diào)用timestamp時如何顯示:
#!/usr/bin/envpython3
importtime
#更新代碼
defTimer(msg):
print(str(msg)+str(time.time()))
現(xiàn)在函數(shù)比以前更抽象了。它仍會打印時間戳,但是它為用戶打印的內(nèi)容msg還是未定義的。這意味著你需要在調(diào)用函數(shù)時定義它。
Timer函數(shù)接受的msg參數(shù)是隨便命名的,你可以使用參數(shù)m、message或text,或是任何對你來說有意義的名稱。重要的是,當(dāng)調(diào)用timestamp.Timer函數(shù)時,它接收一個文本作為其輸入,將接收到的任何內(nèi)容放入msg變量中,并使用該變量完成任務(wù)。
以下是一個測試測試用戶正確感知時間流逝能力的新程序:
#!/usr/bin/envpython3
frommymodularityimporttimestamp
print("PresstheRETURNkey.Countto3,andpressRETURNagain.")
input()
timestamp.Timer("Startedtimerat")
print("Countto3...")
input()
timestamp.Timer("Yousleptuntil")
將你的新程序保存為response.py,運行它:
$python3./response.py
PresstheRETURNkey.Countto3,andpressRETURNagain.
Startedtimerat1560714482.3772075
Countto3...
Yousleptuntil1560714484.1628013
函數(shù)和所需參數(shù)
新版本的timestamp模塊現(xiàn)在需要一個msg參數(shù)。這很重要,因為你的第一個應(yīng)用程序?qū)o法運行,因為它沒有將字符串傳遞給timestamp.Timer函數(shù):
$python3./sleeptest.py
TestingPythonsleep()...
Traceback(mostrecentcalllast):
File"./sleeptest.py",line8,in
timestamp.Timer()
TypeError:Timer()missing1requiredpositionalargument:'msg'
你能修復(fù)你的sleeptest.py應(yīng)用程序,以便它能夠與更新后的模塊一起正確運行嗎?
變量和函數(shù)
通過設(shè)計,函數(shù)限制了變量的范圍。換句話說,如果在函數(shù)內(nèi)創(chuàng)建一個變量,那么這個變量只在這個函數(shù)內(nèi)起作用。如果你嘗試在函數(shù)外部使用函數(shù)內(nèi)部出現(xiàn)的變量,就會發(fā)生錯誤。
下面是對response.py應(yīng)用程序的修改,嘗試從timestamp.Timer()函數(shù)外部打印msg變量:
#!/usr/bin/envpython3
frommymodularityimporttimestamp
print("PresstheRETURNkey.Countto3,andpressRETURNagain.")
input()
timestamp.Timer("Startedtimerat")
print("Countto3...")
input()
timestamp.Timer("Yousleptfor")
print(msg)
試著運行它,查看錯誤:
$python3./response.py
PresstheRETURNkey.Countto3,andpressRETURNagain.
Startedtimerat1560719527.7862902
Countto3...
Yousleptfor1560719528.135406
Traceback(mostrecentcalllast):
File"./response.py",line15,in
print(msg)
NameError:name'msg'isnotdefined
應(yīng)用程序返回一個NameError消息,因為沒有定義msg。這看起來令人困惑,因為你編寫的代碼定義了msg,但你對代碼的了解比Python更深入。調(diào)用函數(shù)的代碼,不管函數(shù)是出現(xiàn)在同一個文件中,還是打包為模塊,都不知道函數(shù)內(nèi)部發(fā)生了什么。一個函數(shù)獨立地執(zhí)行它的計算,并返回你想要它返回的內(nèi)容。這其中所涉及的任何變量都只是本地的:它們只存在于函數(shù)中,并且只存在于函數(shù)完成其目的所需時間內(nèi)。
Return語句
如果你的應(yīng)用程序需要函數(shù)中特定包含的信息,那么使用return語句讓函數(shù)在運行后返回有意義的數(shù)據(jù)。
時間就是金錢,所以修改timestamp函數(shù),以使其用于一個虛構(gòu)的收費系統(tǒng):
#!/usr/bin/envpython3
importtime
defTimer(msg):
print(str(msg)+str(time.time()))
charge=.02
returncharge
現(xiàn)在,timestamp模塊每次調(diào)用都收費2美分,但最重要的是,它返回每次調(diào)用時所收取的金額。
以下一個如何使用return語句的演示:
#!/usr/bin/envpython3
frommymodularityimporttimestamp
print("PressRETURNforthetime(costs2cents).")
print("PressQRETURNtoquit.")
total=0
whileTrue:
kbd=input()
ifkbd.lower()=="q":
print("Youowe$"+str(total))
exit()
else:
charge=timestamp.Timer("Timeis")
total=total+charge
在這個示例代碼中,變量charge為timestamp.Timer()函數(shù)的返回,它接收函數(shù)返回的任何內(nèi)容。在本例中,函數(shù)返回一個數(shù)字,因此使用一個名為total的新變量來跟蹤已經(jīng)進行了多少更改。當(dāng)應(yīng)用程序收到要退出的信號時,它會打印總花費:
$python3./charge.py
PressRETURNforthetime(costs2cents).
PressQRETURNtoquit.
Timeis1560722430.345412
Timeis1560722430.933996
Timeis1560722434.6027434
Timeis1560722438.612629
Timeis1560722439.3649364
q
Youowe$0.1
內(nèi)聯(lián)函數(shù)
函數(shù)不必在單獨的文件中創(chuàng)建。如果你只是針對一個任務(wù)編寫一個簡短的腳本,那么在同一個文件中編寫函數(shù)可能更有意義。唯一的區(qū)別是你不必導(dǎo)入自己的模塊,但函數(shù)的工作方式是一樣的。以下是時間測試應(yīng)用程序的最新迭代:
#!/usr/bin/envpython3
importtime
total=0
defTimer(msg):
print(str(msg)+str(time.time()))
charge=.02
returncharge
print("PressRETURNforthetime(costs2cents).")
print("PressQRETURNtoquit.")
whileTrue:
kbd=input()
ifkbd.lower()=="q":
print("Youowe$"+str(total))
exit()
else:
charge=Timer("Timeis")
total=total+charge
它沒有外部依賴(Python發(fā)行版中包含time模塊),產(chǎn)生與模塊化版本相同的結(jié)果。它的優(yōu)點是一切都位于一個文件中,缺點是你不能在其他腳本中使用Timer()函數(shù),除非你手動復(fù)制和粘貼它。
全局變量
在函數(shù)外部創(chuàng)建的變量沒有限制作用域,因此它被視為全局變量。
全局變量的一個例子是在charge.py中用于跟蹤當(dāng)前花費的total變量。total是在函數(shù)之外創(chuàng)建的,因此它綁定到應(yīng)用程序而不是特定函數(shù)。
應(yīng)用程序中的函數(shù)可以訪問全局變量,但要將變量傳入導(dǎo)入的模塊,你必須像發(fā)送msg變量一樣將變量傳入模塊。
全局變量很方便,因為它們似乎隨時隨地都可用,但也很難跟蹤它們,很難知道哪些變量不再需要了但是仍然在系統(tǒng)內(nèi)存中停留(盡管Python有非常好的垃圾收集機制)。
但是,全局變量很重要,因為不是所有的變量都可以是函數(shù)或類的本地變量?,F(xiàn)在你知道了如何向函數(shù)傳入變量并獲得返回,事情就變得容易了。
以上內(nèi)容為大家介紹了使用Python函數(shù)進行模塊化,希望對大家有所幫助,如果想要了解更多Python相關(guān)知識,請關(guān)注IT培訓(xùn)機構(gòu):千鋒教育。http://m.2667701.com/