• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看

      ?

      淺談如何寫出整潔的Python代碼

      2025-01-11 00:00:00石也牧
      科技風 2025年1期

      摘要:很多人在編寫Python代碼時,只注重相關(guān)功能的實現(xiàn),并不關(guān)心代碼的整潔性。當軟件的代碼量達到一定規(guī)模后,不少開發(fā)者感到代碼越來越混亂、越來越難以維護。學習Python語言,不能只關(guān)注語法規(guī)則的掌握。通過代碼示例,文章闡述了與提高軟件代碼整潔性相關(guān)的幾個方面內(nèi)容:寫代碼時,要注意可讀性;要撰寫功能單一且功能清晰的函數(shù);應充分利用裝飾器、生成器和迭代器等Python獨有的特性,寫出高效的代碼;應了解并經(jīng)常使用Python軟件質(zhì)量保證工具Unittest、Pytest、Pylint和Flake8等測試和掃描代碼。

      關(guān)鍵詞:編程規(guī)范;代碼可讀性;軟件可維護性;單元測試

      BriefDiscussiononHowtoWriteCleanPythonCode

      ShiYemu

      FacultyofAIinEducation,CentralChinaNormalUniversityHubeiWuhan430079

      Abstract:WhenwritingPythoncode,manypeopleonlyfocusontheimplementationofrelatedfunctionsanddonotcareaboutthecleanlinessofthecode.Whentheamount?;ofsoftwarecodereachesacertainscale,manydevelopersfeelthatthecodebecomesincreasinglyconfusinganddifficulttomaintain.WhenlearningthePythonlanguage,youcan'tjustfocusonmasteringthegrammaticalrules.Throughexamples,thisarticleexplainsseveralaspectsrelatedtoimprovingthecleanlinessofsoftwarecode:payattentiontoreadabilitywhilewritingcode;writefunctionswithsingleandclearintention;makefulluseofdecorators,generatorsanditerators,whicharePython'sspecialfeatures,towriteefficientcode;youshouldunderstandandfrequentlyusePythonSWqualityassurancetoolssuchasunittest,pytest,pylintandflake8,etc.,totestandscanyourcode.

      Keywords:Programmingspecifications;codereadability;softwaremaintainability;unittest

      實現(xiàn)同樣的功能,不同的程序員寫出來的代碼完全不一樣,有的人寫的代碼很長,既不容易讀懂又很難維護,軟件的可維護性差,會降低工作效率,相應的項目會越來越難以持續(xù)下去,嚴重的會導致項目組不得不重新設計、編寫代碼。有的軟件作者,在不同時期寫的代碼風格不一樣。有的項目組,每個人都有自己的風格,組內(nèi)風格不統(tǒng)一,大家溝通起來不順暢。這些情況的出現(xiàn),都是因為程序員沒有注意到代碼的整潔性。本文通過舉例,論述了為寫出整潔的代碼而需要注意的幾個地方。

      1要有好的可讀性

      針對邏輯上并不復雜的功能需求,有的編程者寫的代碼別人很難讀懂,有的人看不明白自己幾個月前寫的代碼,這都是因為代碼的可讀性差??勺x性不好的軟件,維護起來非常不容易。

      寫代碼的同時,要寫相應的注釋,寫代碼和寫注釋要做到同步;注釋要有一定的占比,不能可有可無;定義函數(shù)的時候,要有函數(shù)功能和各個參數(shù)說明的注釋;定義類的時候,類的每個屬性和方法都要有相應的注釋;修改代碼的時候,相應的注釋也必須修改。雖然注釋不參與編譯、不參與程序的運行,但注釋非常重要,要把注釋看作是程序的一個組成部分。

      除了增加注釋外,文件名、變量名、函數(shù)名和類名等要盡可能地做到顧名思義和一望而知[1],不要讓閱讀代碼的人(包括將來的自己)去猜。例如:

      classPerson:

      def__init__(self,name,email,phone):

      self.name=name

      self.email=email

      self.phone=phone

      顯然,類Person的初始化函數(shù)記錄了人名、郵箱和電話。寫代碼能做到見其名知其意很好,但也不要過度。例如,下面的代碼和前面相比,很詳盡,但并沒有增加可讀性,反而讓人覺得過于啰唆:

      classPerson:

      def__init__(self,personal_username,personal_email_address,personl_telephone_number):

      self.personal_username=personal_username

      self.personal_email_address=personal_email_address

      self.personal_telephone_num=personal_telephone_number

      2函數(shù)功能要單一

      假設有如下函數(shù),功能是取得一個列表,然后打印該列表的所有元素:

      deffetch_and_show_users():

      users=[…]#由某算法得到列表

      foruserinusers:

      print(user)#顯示列表

      這個函數(shù)有兩個功能,但有的用戶只需要得到列表,而有的用戶只想顯示列表。這時,對于某些調(diào)用該函數(shù)的用戶而言,代碼里出現(xiàn)了累贅,這增加了代碼的冗余,多余的步驟對程序的調(diào)試會造成干擾。把前面的函數(shù)分解為如下的兩個函數(shù),非常方便于用戶的調(diào)用:

      deffetch_users():

      users=[]#由某算法得到列表

      returnusers

      defdisplay_users(users):

      foruserinusers:

      print(user)#顯示列表

      再舉個例子,某個函數(shù)具備下載、解壓縮和按照某種規(guī)則選取解壓之后文件的功能,最好將這個函數(shù)分解。否則,可能會出現(xiàn)這樣的情況:有的用戶只是想下載某個壓縮包而調(diào)用了該函數(shù),他不得不等著解壓縮和選取文件這兩個他并不需要的步驟完成。

      不僅是函數(shù),還有類和模塊,都應功能單一,只做一件事而且要將事情做好[2]。

      3函數(shù)功能要清晰

      先看如下轉(zhuǎn)換大小寫的函數(shù),該函數(shù)的作用不難理解:

      deftransform_text(text,uppercase):

      ifuppercase:

      returntext.upper()

      else:

      returntext.lower()

      顯然,當調(diào)用transform_text(text,True)時,字符串text中的小寫字母都轉(zhuǎn)換為大寫;當調(diào)用transform_text(text,F(xiàn)alse)時,字符串text中的大寫字母都轉(zhuǎn)換為小寫。如果不看函數(shù)transform_text的定義,僅僅看transform_text(text,True/False),很難知道它在做什么。

      將上面的函數(shù)分為如下兩個函數(shù):

      defturn_to_uppercase(text):

      returntext.upper()

      defturn_to_lowercase(text):

      returntext.lower()

      當調(diào)用turn_to_uppercase(text)時,字符串text中的小寫字母都轉(zhuǎn)換為大寫;當調(diào)用turn_to_lowercase(text)時,字符串text中的大寫字母都轉(zhuǎn)換為小寫。這時,僅僅看turn_to_uppercase(text)或者turn_to_lowercase(text),就知道在做什么。函數(shù)的功能要做到清晰明確[3]。

      在調(diào)用函數(shù)遇到關(guān)鍵字參數(shù)的時候,帶上關(guān)鍵字名字可以增強可讀性,而且不必擔心參數(shù)的次序?qū)戝e。例如,SendMail(from=a@x.com,to=b@y.com)比SendMail(a@x.com,b@y.com)的可讀性強很多,用意一目了然,就像在讀簡單明了的英文句子。

      4使用更Pythonic的語法

      Python代碼要有“Python的味道”,同等條件下,代碼要寫得Pythonic一些。例如,遍歷一個列表,可用如下for循環(huán):

      forkinrange(len(a_list)):

      print('index:',k,'value:',a_list[k])

      上面的代碼是正確的,但這是傳統(tǒng)編程語言的方法。作為Python程序員,應使用針對可迭代對象的內(nèi)置函數(shù)enumerate:

      forindex,iteminenumerate(a_list):

      print('index:',index,'value:',item)

      交換兩個變量a和b的值,傳統(tǒng)語言的代碼如下:

      tmp=b

      b=a

      a=tmp

      Python代碼這樣寫也是沒有問題的。實際上,Python語言有如下簡便的寫法,用以交換a和b的值:

      a,b=b,a

      判斷字符串的前綴與后綴,可以使用內(nèi)置的字符串方法startswith和endswith,也可以使用切片。例如,如下if語句作用是相同的:

      sentence="Helloeveryone,goodmorning"

      ifsentence.startswith("Hello"):……

      ifsentence[:5]=="Hello":……

      ifsentence.endswith("morning"):……

      ifsentence[-7:]=="morning":……

      很明顯,startswith和endswith的可讀性更好,使用切片的話,可讀性下降,而且容易將字母的個數(shù)寫錯。

      對一個列表的每個元素進行相同的操作,使用map和列表推導都可以。例如:

      >>>nums=[1,2,3,4,5]

      >>>squares=list(map(lambdax:x**2,nums))

      >>>squares

      [1,4,9,16,25]

      >>>squares=[x**2forxinnums]

      >>>squares

      [1,4,9,16,25]

      顯然,列表推導的可讀性更強、形式上簡單,而且列表推導的速度比map快,運行效率高。完成同樣的任務,應盡可能使用列表推導而不是map。

      5充分利用Python的獨有特性

      裝飾器本身是一個函數(shù),裝飾器的返回值是一個函數(shù)對象,裝飾器可以讓其他函數(shù)在不需要做任何代碼變動的前提下增加額外功能[4]。例如,有N個函數(shù),現(xiàn)在要給它們增加函數(shù)日志和函數(shù)性能測試的功能。如果是傳統(tǒng)編程語言,需要對每個函數(shù)進行修改。對于Python而言,不需要進行N次類似甚至同樣的修改。定義一個裝飾器decorator,對函數(shù)進行封裝,添加所需的功能(日志和性能測試),然后在每個函數(shù)的頭部添加一行@decorator即可,N個函數(shù)的原始代碼保持不變。這樣保證了代碼的穩(wěn)定性,在減少重復勞動的同時,增加了函數(shù)的功能。

      生成器支持延遲計算,在需要的時候可以生成相應的值,而不是一次性地生成整個序列。生成器特別適合于大型數(shù)據(jù)處理,使用生成器,可以減少內(nèi)存使用,優(yōu)化代碼,提高程序的效率。

      6使用Unittest和Pytest進行測試

      有的程序員寫了很長時間的代碼,但從未對自己的代碼進行過單元測試,只有在程序運行遇到錯誤時才開始檢查當中的問題。單元測試是用來對函數(shù)、類或者模塊進行正確性檢驗的工作[5]。如果代碼都通過了單元測試,那么軟件的質(zhì)量將大大提高。Unittest是Python自帶的測試框架,例如,如下代碼使用斷言來測試函數(shù)square()是否正確:

      importunittest

      defsquare(a):

      returna*a

      classST(unittest.TestCase):

      deftest_square(self):

      self.assertEqual(square(7),49)

      if__name__=="__main__":

      unittest.main()

      Pytest是一個第三方的測試框架,兼容Unittest,比Unittest框架使用起來更簡潔,效率更高,使用命令pipinstallpytest安裝它。Pytest編寫測試用例很容易,用例可以是類的形式,也可以是函數(shù)的形式。例如,如下代碼用來測試函數(shù)double()的正確性:

      defdouble(x):

      return3*x

      deftest_dbl():

      assertdouble(8)==16

      運行pytest,結(jié)果為:

      deftest_dbl():

      >assertdouble(8)==16

      Eassert24==16

      E+where24=double(8)

      test.py:4:AssertionError

      根據(jù)輸出,很容易看到問題所在,將函數(shù)double()中的3*x改為2*x就解決了。

      7使用Pylint等工具檢查代碼

      在項目編碼完成或者階段性完成后,應該使用質(zhì)量保證工具對代碼進行掃描,就像體檢一樣。Pylint是一個針對Python代碼中的語法錯誤、潛在問題和代碼風格的靜態(tài)檢查工具,使用pipinstallpylint命令安裝它。下面的代碼一共三行,看上去沒有任何問題:

      defadd_one(x):

      returnx+1;

      print(add_one(15))

      運行命令python3mpylint<文件名>,用Pylint分析這三行看似正確且毫無瑕疵的代碼,得到的結(jié)果為:

      2:0:W0311:Badindentation.Found3spaces,expected4(badindentation)

      2:0:W0301:Unnecessarysemicolon(unnecessarysemicolon)

      1:0:C0114:Missingmoduledocstring(missingmoduledocstring)

      1:0:C0116:Missingfunctionormethoddocstring(missingfunctiondocstring)

      短短的三行代碼,掃描出了四個問題:(1)第二行的縮進是三個空格,最好是四個空格;(2)第二行結(jié)尾的分號沒有必要;(3)文件沒有注釋說明;(4)函數(shù)也沒有注釋說明。修改如下,再使用Pylint掃描就沒有問題了:

      '''Thispythonscriptisforpylintstudy'''

      defadd_one(x):

      '''inputparameterisanumber,

      add1tothenumber,andreturn'''

      returnx+1

      print(add_one(15))

      8學習PEP8

      除了語法,程序員也要學習編碼規(guī)范方面的知識。PEP8是Python編碼規(guī)范指南,PEP是PythonEnhancementProposals的簡寫,遵循該規(guī)范可以讓開發(fā)者寫出整潔的代碼,提高代碼的可讀性,有助于同一個項目組內(nèi)大家的編碼風格保持一致[6]。使用工具Pycodestyle可以檢查代碼是否遵從PEP8,運行命令pipinstallpycodestyle安裝它。如下是非常簡短的四行代碼:

      a=1

      b=2

      print(a==b)

      if(b>a):print("bisbigger")

      運行命令pycodestyle<文件名>,檢測這四行代碼,結(jié)果如下:

      1:2:E225missingwhitespacearoundoperator

      3:6:E211whitespacebefore'('

      4:3:E275missingwhitespaceafterkeyword

      4:10:E231missingwhitespaceafter':'

      4:10:E701multiplestatementsononeline(colon)

      使用Pycodestyle發(fā)現(xiàn)的問題有:a=1的等號兩邊應該有空格;print和(之間的空格是不需要的;關(guān)鍵字if的后面應該有空格;最后一行最好分為兩行。將代碼修改如下,再使用Pycodestyle掃描就沒有問題了:

      a=1

      b=2

      print(a==b)

      ifb>a:

      print("bisbigger")

      工具Flake8的功能比Pycodestyle更加強大,安裝命令為pipinstallflake8。Flake8將Pyflakes(類似于Pylint)、Pycodestyle和McCabe(代碼復雜性檢查器)整合到一起,使用它可以一次性檢查出多種問題。Flake8非常易于與其他工具結(jié)合,比如,在集成開發(fā)環(huán)境PyCharm中配置Flake8非常簡單。

      結(jié)語

      Python誕生于1991年,近些年,Python語言已經(jīng)滲透到各個領(lǐng)域,使用Python的人越來越多。Python用戶不能僅僅學語法,還應該了解如何讓代碼變得更整潔。軟件的維護期一般長于(甚至遠遠長于)開發(fā)期,不整潔的代碼很難提高工作效率。作為Python開發(fā)人員,要想寫出整潔的代碼,除了語法規(guī)則之外,需要了解的知識點比較多,很難用一篇短文完全闡述清楚。希望本文能給新Python程序員一點啟發(fā),為代碼質(zhì)量的提升提供些許幫助。

      參考文獻:

      [1]HarshitTyagi.PythonicCode:BestPracticestoMakeYourPythonMoreReadable[EB/OL].(20220530).https://www.codementor.io/blog/pythoniccode6yxqdoktzt.

      [2]AlexOmeyer.10MustKnowPatternsforWritingCleanCodeWithPython[EB/OL].(20220406).https://dzone.com/articles/10mustknowpatternsforwritingcleancodewith1.

      [3]KhuyenTran.PythonCleanCode:6BestPracticestoMakeYourPythonFunctionsMoreReadable[EB/OL].(20210121).https://towardsdatascience.com/pythoncleancode6bestpracticestomakeyourpythonfunctionsmorereadable7ea4c6171d60.

      [4]蘇尼爾·卡皮爾.Python代碼整潔之道編寫優(yōu)雅的代碼[M].連少華,譯.北京:機械工業(yè)出版社,2020.

      [5]馬里西諾·阿納亞.編寫整潔的Python代碼[M].包永帥,譯.北京:人民郵電出版社,2021.

      [6]ThePEPEditors.IndexofPythonEnhancementProposals[EB/OL].(20000713).https://peps.python.org/.

      作者簡介:石也牧(2004—),女,漢族,北京人,本科,研究方向:人工智能。

      庆云县| 淮南市| 湘阴县| 明水县| 安国市| 平山县| 会理县| 肥西县| 乌兰县| 霸州市| 丰都县| 固阳县| 甘洛县| 黄浦区| 广元市| 永清县| 高阳县| 托克托县| 弋阳县| 遂宁市| 北京市| 鹰潭市| 涪陵区| 中西区| 正定县| 于田县| 秀山| 西充县| 高陵县| 区。| 陇川县| 巩留县| 晋宁县| 普兰店市| 武义县| 建德市| 海安县| 娄烦县| 无极县| 玛曲县| 廉江市|