定義與調(diào)用:代碼復(fù)用與作用域?qū)崙?zhàn)指南)
在日常寫(xiě) Python 的時(shí)候函數(shù)定義與調(diào)用大概是最常碰到的語(yǔ)法之一。不管你是剛接觸編程的新手還是已經(jīng)寫(xiě)了幾年業(yè)務(wù)邏輯的老手幾乎每個(gè)腳本里都少不了def這個(gè)詞。很多人的函數(shù)用法停留在“能跑就行”的階段能定義、能調(diào)用、能傳參、能返回就覺(jué)得自己會(huì)了。但函數(shù)真正的價(jià)值并不在于跑通某個(gè)腳本而在于代碼復(fù)用和邏輯拆分。我寫(xiě)這篇文章就是想聊透這件事函數(shù)為什么是編寫(xiě)可重用代碼的基石怎么把一個(gè)功能定義成整潔易懂的函數(shù)以及調(diào)用時(shí)那些最容易踩的坑到底怎么避開(kāi)。要把函數(shù)用好需要理解的不只是def關(guān)鍵字。參數(shù)的傳遞機(jī)制、作用域的查找規(guī)則、返回值的處理方式、函數(shù)的文檔規(guī)范這些串在一起才是一個(gè)完整的函數(shù)設(shè)計(jì)。這篇文章從最基礎(chǔ)的語(yǔ)法講起逐步深入到參數(shù)細(xì)節(jié)、作用域規(guī)則、常見(jiàn)報(bào)錯(cuò)和排查技巧既有可以直接復(fù)制的代碼示例也有我在實(shí)際項(xiàng)目里積累的經(jīng)驗(yàn)教訓(xùn)。無(wú)論你是第一次接觸函數(shù)定義與調(diào)用還是想系統(tǒng)地梳理自己的知識(shí)盲區(qū)這里的內(nèi)容都能幫上忙。1. 函數(shù)是什么從重復(fù)代碼到模塊化思維1.1 一段常見(jiàn)的重復(fù)代碼引發(fā)的思考先看一個(gè)我在很多初學(xué)項(xiàng)目里都見(jiàn)過(guò)的場(chǎng)景。某同學(xué)寫(xiě)了一個(gè)處理人員信息的腳本需要分別計(jì)算三組人的平均年齡于是代碼長(zhǎng)這樣ages_1 [23, 25, 31, 28, 35] total 0 for age in ages_1: total age avg_1 total / len(ages_1) print(f第一組平均年齡: {avg_1}) ages_2 [26, 29, 30, 27, 32, 28] total 0 for age in ages_2: total age avg_2 total / len(ages_2) print(f第二組平均年齡: {avg_2}) ages_3 [21, 24, 26, 25] total 0 for age in ages_3: total age avg_3 total / len(ages_3) print(f第三組平均年齡: {avg_3})這段代碼能運(yùn)行也能輸出正確結(jié)果但問(wèn)題非常明顯同樣的“累加再除以個(gè)數(shù)”邏輯被完整復(fù)制了三遍。如果某天需求變了比如要改成先去掉最大值再算平均你就得在三處地方分別修改漏改一處就會(huì)造成結(jié)果不一致。這種重復(fù)正是代碼腐化的開(kāi)始也是函數(shù)定義與調(diào)用要解決的核心問(wèn)題。上面的場(chǎng)景換用函數(shù)來(lái)表達(dá)只需要把公共邏輯提取出來(lái)一次def average(ages): total 0 for age in ages: total age return total / len(ages) avg_1 average([23, 25, 31, 28, 35]) avg_2 average([26, 29, 30, 27, 32, 28]) avg_3 average([21, 24, 26, 25]) print(avg_1, avg_2, avg_3)需求變更時(shí)只需要修改average這一個(gè)函數(shù)體所有調(diào)用處自動(dòng)生效。1.2 函數(shù)的本質(zhì)輸入-處理-輸出模型函數(shù)從本質(zhì)上看是一個(gè)非常樸素的概念接收輸入執(zhí)行處理返回輸出。就像一臺(tái)榨汁機(jī)你放進(jìn)去蘋(píng)果得到蘋(píng)果汁放進(jìn)去橙子得到橙汁。至于內(nèi)部是怎么榨的調(diào)用者不用關(guān)心只需要知道“放什么進(jìn)去、能得到什么”就行了。這就是函數(shù)最重要的特性封裝。封裝帶來(lái)的直接好處是接口與實(shí)現(xiàn)分離。函數(shù)的調(diào)用者只需要關(guān)心參數(shù)和返回值不需要了解內(nèi)部每一行代碼的含義。這種抽象能力讓程序的可維護(hù)性大幅提升也讓我在團(tuán)隊(duì)協(xié)作時(shí)能明確劃分邊界寫(xiě)函數(shù)的人負(fù)責(zé)保證功能正確用函數(shù)的人負(fù)責(zé)把合適的輸入傳進(jìn)去并處理返回值。1.3 函數(shù)定義與調(diào)用最簡(jiǎn)形式Python 用來(lái)定義函數(shù)的關(guān)鍵字是def最簡(jiǎn)單的形式如下def greet(): print(你好歡迎學(xué)習(xí) Python)調(diào)用時(shí)就是函數(shù)名加一對(duì)括號(hào)greet()這個(gè)函數(shù)沒(méi)有參數(shù)也沒(méi)有返回值僅僅是在調(diào)用時(shí)執(zhí)行了一次打印。雖然簡(jiǎn)單但它已經(jīng)完整展示了函數(shù)的三個(gè)基本組成函數(shù)名greet、函數(shù)體縮進(jìn)的print語(yǔ)句、以及由括號(hào)標(biāo)識(shí)的調(diào)用語(yǔ)法。實(shí)際項(xiàng)目里函數(shù)很少這么簡(jiǎn)單更多時(shí)候它需要接收參數(shù)并返回計(jì)算結(jié)果這些在后面詳細(xì)展開(kāi)。2. 函數(shù)定義與調(diào)用的核心細(xì)節(jié)解析2.1 def語(yǔ)句的完整結(jié)構(gòu)拆解一個(gè)標(biāo)準(zhǔn)的函數(shù)定義包含五個(gè)部分def關(guān)鍵字、函數(shù)名、參數(shù)列表、冒號(hào)、函數(shù)體。函數(shù)名要遵循 Python 的命名規(guī)范通常使用小寫(xiě)字母加下劃線比如calculate_total、read_user_data。參數(shù)列表寫(xiě)在括號(hào)內(nèi)可以為空也可以有一個(gè)或多個(gè)參數(shù)。函數(shù)體必須縮進(jìn)Python 通過(guò)縮進(jìn)來(lái)界定函數(shù)的代碼范圍。函數(shù)體內(nèi)部最常見(jiàn)的語(yǔ)句是return它的作用有兩個(gè)一是結(jié)束函數(shù)執(zhí)行二是把結(jié)果返回給調(diào)用者。如果函數(shù)沒(méi)有return語(yǔ)句Python 會(huì)默認(rèn)返回None。這一點(diǎn)很多人容易忽略我曾經(jīng)在排查一個(gè)問(wèn)題時(shí)發(fā)現(xiàn)有個(gè)函數(shù)計(jì)算了半天卻拿到None原因就是函數(shù)體內(nèi)只賦值了結(jié)果變量卻忘記寫(xiě)return。這類(lèi)問(wèn)題不報(bào)錯(cuò)所以排查起來(lái)特別隱蔽。先看一個(gè)包含完整要素的函數(shù)def add(a, b): result a b return result sum_value add(3, 5) print(sum_value) # 輸出 8這段代碼里add是函數(shù)名a和b是兩個(gè)參數(shù)result a b是處理邏輯return result把計(jì)算結(jié)果返回給調(diào)用方。調(diào)用后sum_value接收返回值并參與后續(xù)邏輯。2.2 參數(shù)傳遞位置參數(shù)、關(guān)鍵字參數(shù)與默認(rèn)值函數(shù)的參數(shù)傳遞是最值得花時(shí)間研究的部分。先說(shuō)位置參數(shù)這是最直觀的方式調(diào)用時(shí)按順序把值傳給函數(shù)定義里的形參def introduce(name, age): print(f我是{name}今年{age}歲) introduce(張三, 25) # 位置參數(shù)按順序?qū)?yīng)只要參數(shù)順序?qū)戝e(cuò)結(jié)果就會(huì)出錯(cuò)。為了增強(qiáng)可讀性和健壯性Python 提供了關(guān)鍵字參數(shù)調(diào)用時(shí)用參數(shù)名值的方式顯式傳遞introduce(age25, name張三)關(guān)鍵字參數(shù)的好處是不用擔(dān)心順序問(wèn)題尤其是當(dāng)函數(shù)參數(shù)較多時(shí)這個(gè)優(yōu)勢(shì)特別明顯。我在實(shí)際項(xiàng)目中封裝數(shù)據(jù)處理函數(shù)時(shí)通常習(xí)慣在調(diào)用處用關(guān)鍵字參數(shù)雖然多打幾個(gè)字但代碼的可讀性提升非常明顯。別人讀代碼的時(shí)候一眼就能看出來(lái)每個(gè)值傳給了哪個(gè)參數(shù)。默認(rèn)值參數(shù)是另一個(gè)重要的設(shè)計(jì)手段。有些參數(shù)在大多數(shù)情況下都用同一個(gè)值只有在特殊場(chǎng)景才需要改變這時(shí)就可以給它一個(gè)默認(rèn)值def connect(host, port3306): print(f連接 {host}:{port}) connect(localhost) # 使用默認(rèn)端口 3306 connect(localhost, 5432) # 覆蓋默認(rèn)值使用 5432這里涉及一個(gè)重要的規(guī)則帶默認(rèn)值的參數(shù)必須放在不帶默認(rèn)值的參數(shù)之后。換句話說(shuō)def connect(port3306, host)是語(yǔ)法錯(cuò)誤。原因很簡(jiǎn)單如果允許默認(rèn)參數(shù)在前那么調(diào)用connect(localhost)時(shí)解釋器會(huì)把這個(gè)值賦給port還是host規(guī)則不清晰。Python 選擇用“必須靠后”來(lái)消除歧義。2.3 return的返回值行為與常見(jiàn)誤區(qū)return是函數(shù)與外部世界溝通的主要通道。理解它有幾個(gè)關(guān)鍵點(diǎn)。首先return可以返回任意類(lèi)型的對(duì)象包括數(shù)字、字符串、列表、字典甚至另一個(gè)函數(shù)def make_adder(n): def adder(x): return x n return adder add_five make_adder(5) print(add_five(10)) # 輸出 15其次一個(gè)函數(shù)可以有多個(gè)return分支但運(yùn)行時(shí)只會(huì)執(zhí)行其中一個(gè)。比如判斷奇偶性的函數(shù)def even_or_odd(num): if num % 2 0: return 偶數(shù) else: return 奇數(shù)第三return之后的代碼永遠(yuǎn)不會(huì)執(zhí)行。有些初學(xué)者會(huì)在return后面繼續(xù)寫(xiě)清理邏輯結(jié)果發(fā)現(xiàn)那部分代碼從未被調(diào)用這就是沒(méi)有理解“return同時(shí)終結(jié)函數(shù)執(zhí)行”這一行為。另一個(gè)容易出問(wèn)題的點(diǎn)是return和print的混淆。print只是把內(nèi)容輸出到控制臺(tái)并不把數(shù)據(jù)返回給調(diào)用者。而return是把結(jié)果交給調(diào)用方的邏輯后續(xù)代碼可以繼續(xù)使用這個(gè)值。下面這兩段代碼的行為完全不同def show_value(): print(42) def get_value(): return 42調(diào)用show_value()會(huì)輸出 42但這個(gè)函數(shù)本身返回的是None。調(diào)用get_value()同樣會(huì)得到 42但如果直接用一句get_value()而不做賦值解釋器不會(huì)在控制臺(tái)打印任何內(nèi)容因?yàn)榉祷刂禌](méi)有被使用。想看到返回值就必須配合printprint(get_value())3. 實(shí)操過(guò)程從零構(gòu)建一個(gè)可復(fù)用的溫度轉(zhuǎn)換函數(shù)3.1 需求分析與函數(shù)設(shè)計(jì)現(xiàn)在用一個(gè)完整的例子來(lái)演示函數(shù)設(shè)計(jì)的過(guò)程。假設(shè)我們要寫(xiě)一個(gè)溫度轉(zhuǎn)換工具把攝氏溫度轉(zhuǎn)換為華氏溫度并且要支持批量轉(zhuǎn)換。這個(gè)工具涉及三個(gè)核心需求單個(gè)數(shù)值轉(zhuǎn)換、批量數(shù)據(jù)轉(zhuǎn)換、以及格式化的輸出。設(shè)計(jì)函數(shù)時(shí)首先考慮接口。單個(gè)轉(zhuǎn)換函數(shù)接收一個(gè)攝氏度數(shù)值返回一個(gè)華氏度數(shù)值。轉(zhuǎn)換公式是華氏度 攝氏度 × 9 / 5 32。這里有個(gè)小細(xì)節(jié)值得注意用整數(shù)還是浮點(diǎn)數(shù)攝氏溫度可能帶小數(shù)所以參數(shù)應(yīng)該能接收浮點(diǎn)數(shù)計(jì)算時(shí)直接使用除法而不是整除def celsius_to_fahrenheit(celsius): fahrenheit celsius * 9 / 5 32 return fahrenheit實(shí)現(xiàn)了單個(gè)轉(zhuǎn)換后批量轉(zhuǎn)換可以直接利用這個(gè)函數(shù)。這里體現(xiàn)了函數(shù)復(fù)用的核心價(jià)值——一個(gè)基礎(chǔ)函數(shù)被另一個(gè)業(yè)務(wù)函數(shù)調(diào)用而不是重新寫(xiě)一遍換算邏輯def convert_batch(celsius_list): result [] for celsius in celsius_list: result.append(celsius_to_fahrenheit(celsius)) return result3.2 完整實(shí)現(xiàn)與調(diào)用示例把格式化的部分也納入考慮可以再加一個(gè)函數(shù)來(lái)展示結(jié)果。關(guān)于函數(shù)的劃分我個(gè)人的經(jīng)驗(yàn)是一個(gè)函數(shù)只做一件事做完了就返回結(jié)果不要在函數(shù)內(nèi)部既計(jì)算又打印又寫(xiě)文件。這樣拆分后每個(gè)函數(shù)都可以單獨(dú)測(cè)試出錯(cuò)時(shí)定位也更方便。下面是一個(gè)相對(duì)完整的示例def celsius_to_fahrenheit(celsius): 將攝氏度轉(zhuǎn)換為華氏度。 return celsius * 9 / 5 32 def convert_batch(celsius_list): 批量轉(zhuǎn)換攝氏度列表為華氏度列表。 return [celsius_to_fahrenheit(c) for c in celsius_list] def display_conversion(celsius): 以易讀的格式展示單個(gè)溫度的轉(zhuǎn)換結(jié)果。 fahrenheit celsius_to_fahrenheit(celsius) print(f{celsius}°C {fahrenheit:.2f}°F) # 調(diào)用測(cè)試 display_conversion(100) # 輸出 100°C 212.00°F result convert_batch([0, 25, 37, 100]) print(result) # 輸出 [32.0, 77.0, 98.6, 212.0]這個(gè)例子里convert_batch使用了列表推導(dǎo)式比傳統(tǒng)的 for 循環(huán)加 append 更簡(jiǎn)潔。它仍然復(fù)用了單個(gè)轉(zhuǎn)換函數(shù)保證核心換算邏輯只維護(hù)一份代碼。3.3 函數(shù)文檔與命名規(guī)范的要點(diǎn)函數(shù)除了要能正確運(yùn)行還要容易被其他開(kāi)發(fā)者理解和使用。這里不得不提 docstring文檔字符串。在函數(shù)定義后的第一行用三引號(hào)寫(xiě)的說(shuō)明文字就是 docstring它可以通過(guò)help()或 IDE 的懸停提示展示給調(diào)用者def celsius_to_fahrenheit(celsius): 將攝氏度轉(zhuǎn)換為華氏度。 參數(shù): celsius: 攝氏溫度值可以是整數(shù)或浮點(diǎn)數(shù)。 返回: 對(duì)應(yīng)的華氏溫度值。 return celsius * 9 / 5 32一個(gè)好的 docstring 應(yīng)該說(shuō)明函數(shù)做什么、參數(shù)是什么、返回什么必要時(shí)附上示例。這不只是給別人看的也是給自己三個(gè)月后看的。我經(jīng)常翻自己以前寫(xiě)的代碼沒(méi)有 docstring 時(shí)真的需要逐行閱讀才能想起來(lái)當(dāng)時(shí)的設(shè)計(jì)意圖。命名規(guī)范同樣重要。函數(shù)名應(yīng)該是一個(gè)動(dòng)詞短語(yǔ)能清晰表達(dá)功能calculate_total、fetch_user_data、validate_email都比do_thing、func1好得多。變量名也要避免過(guò)于簡(jiǎn)寫(xiě)幾十行代碼以內(nèi)的腳本也許還能靠上下文理解代碼一多含義不明的變量名就是最大的閱讀障礙。4. 變量作用域與命名空間理解局部變量和全局變量4.1 作用域規(guī)則與查找順序函數(shù)內(nèi)部定義的變量是局部變量作用范圍僅限于這個(gè)函數(shù)內(nèi)部。函數(shù)外部定義的變量是全局變量理論上模塊內(nèi)所有位置都可以訪問(wèn)。但“可以訪問(wèn)”和“可以修改”是兩回事這正是初學(xué)者最容易暈的地方x 10 # 全局變量 def print_x(): print(x) # 可以讀取全局變量 def set_x(): x 20 # 這是在函數(shù)內(nèi)部創(chuàng)建了一個(gè)新的局部變量不是修改全局變量 print_x() # 輸出 10 set_x() print(x) # 仍然輸出 10當(dāng)函數(shù)內(nèi)部出現(xiàn)x 20時(shí)Python 會(huì)把x當(dāng)作局部變量來(lái)處理哪怕外部已經(jīng)有同名的全局變量。這個(gè)規(guī)則讓很多人困惑為什么我在函數(shù)里賦值了外面的變量沒(méi)變因?yàn)檫@兩個(gè)x壓根不是同一個(gè)變量它們身處不同的命名空間。4.2 global與nonlocal的正確使用方式如果想在函數(shù)內(nèi)部修改全局變量需要顯式聲明globalx 10 def set_x(): global x x 20 set_x() print(x) # 輸出 20類(lèi)似地嵌套函數(shù)中如果想修改外層函數(shù)的局部變量需要使用nonlocaldef outer(): count 0 def inner(): nonlocal count count 1 inner() return count4.3 避免濫用全局變量的設(shè)計(jì)建議我把global列為“能不用就不用”的語(yǔ)法。全局變量在程序運(yùn)行期間始終存在任何位置的代碼都可能修改它這導(dǎo)致排查問(wèn)題時(shí)無(wú)法確定變量值是在哪里被改掉的。函數(shù)應(yīng)該盡量通過(guò)參數(shù)接收輸入、通過(guò)返回值交出結(jié)果保持純粹性。一個(gè)完全不依賴外部可變狀態(tài)的函數(shù)測(cè)試起來(lái)最容易別人讀起來(lái)也最省心。實(shí)操中我發(fā)現(xiàn)很多人遇到“多個(gè)函數(shù)都要用同一個(gè)數(shù)據(jù)”的需求時(shí)第一反應(yīng)是把數(shù)據(jù)定義為全局變量。更好的方式是把這個(gè)數(shù)據(jù)作為參數(shù)傳遞給需要的函數(shù)或者將它封裝在類(lèi)中。哪怕代碼稍顯啰嗦也遠(yuǎn)比隱式的全局依賴更容易維護(hù)。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄5.1 高頻報(bào)錯(cuò)速查表函數(shù)相關(guān)的報(bào)錯(cuò)非常有規(guī)律下面是我遇到最多的幾類(lèi)報(bào)錯(cuò)信息常見(jiàn)原因解決方案NameError: name xxx is not defined函數(shù)名拼寫(xiě)錯(cuò)誤或者在函數(shù)被調(diào)用前還沒(méi)有定義檢查函數(shù)名是否拼寫(xiě)一致確認(rèn)函數(shù)定義在調(diào)用語(yǔ)句之前TypeError: add() missing 1 required positional argument調(diào)用時(shí)少傳了一個(gè)位置參數(shù)檢查函數(shù)定義有幾個(gè)參數(shù)調(diào)用時(shí)是否全部傳入TypeError: add() takes 2 positional arguments but 3 were given調(diào)用時(shí)傳了多余的參數(shù)對(duì)比函數(shù)定義的參數(shù)個(gè)數(shù)IndentationError: expected an indented block函數(shù)體沒(méi)有縮進(jìn)確認(rèn)def下一行有統(tǒng)一的縮進(jìn)SyntaxError: non-default argument follows default argument默認(rèn)值參數(shù)放在了非默認(rèn)參數(shù)前面調(diào)整參數(shù)順序默認(rèn)值參數(shù)必須靠后5.2 我實(shí)際踩過(guò)的幾個(gè)坑第一個(gè)坑是關(guān)于可變參數(shù)默認(rèn)值的??聪旅娴拇adef add_item(item, items[]): items.append(item) return items第一次調(diào)用add_item(1)返回[1]第二次調(diào)用add_item(2)返回[1, 2]這個(gè)結(jié)果會(huì)讓很多人吃驚。原因在于默認(rèn)值是在函數(shù)定義時(shí)創(chuàng)建的后續(xù)所有調(diào)用共享同一個(gè)列表對(duì)象。這幾乎可以確定是設(shè)計(jì)上的缺陷正確寫(xiě)法是使用None作為默認(rèn)值在函數(shù)內(nèi)部再創(chuàng)建新列表def add_item(item, itemsNone): if items is None: items [] items.append(item) return items第二個(gè)坑是變量名遮蔽。曾經(jīng)有個(gè)函數(shù)內(nèi)部習(xí)慣性地把接收到的參數(shù)命名為data而全局也有一個(gè)data結(jié)果在處理邏輯中不小心用到了全局變量排查了很久才發(fā)現(xiàn)問(wèn)題。這類(lèi)問(wèn)題最好的預(yù)防方式是保持命名風(fēng)格的統(tǒng)一并且盡量避免局部變量與全局變量同名。第三個(gè)坑和return有關(guān)是返回了過(guò)早。有一次寫(xiě)一個(gè)遍歷函數(shù)想在指定條件下提前返回結(jié)果結(jié)果return寫(xiě)得太靠前后面的累加邏輯全部被跳過(guò)。這類(lèi)問(wèn)題只能靠仔細(xì)閱讀代碼邏輯來(lái)發(fā)現(xiàn)調(diào)試時(shí)多用print輸出中間值會(huì)很有幫助。5.3 函數(shù)設(shè)計(jì)的一些實(shí)用建議最后分享幾點(diǎn)我在實(shí)際項(xiàng)目中積累的函數(shù)設(shè)計(jì)經(jīng)驗(yàn)。第一函數(shù)越短越好。如果一個(gè)函數(shù)的函數(shù)體超過(guò) 30 行通常說(shuō)明它承擔(dān)了太多職責(zé)應(yīng)該考慮拆分。短函數(shù)更容易測(cè)試也更容易復(fù)用。把一個(gè)完整的業(yè)務(wù)邏輯拆成多個(gè)小函數(shù)并不是代碼過(guò)多而是為后續(xù)維護(hù)留出了空間。第二參數(shù)數(shù)量越少越好。如果一個(gè)函數(shù)需要五六個(gè)甚至更多的參數(shù)很可能是在處理過(guò)多的事情??梢試L試把關(guān)系密切的參數(shù)打包成一個(gè)數(shù)據(jù)結(jié)構(gòu)或?qū)ο笾粋鬟f這一個(gè)對(duì)象。第三函數(shù)的設(shè)計(jì)要以調(diào)用者的視角為中心。寫(xiě)函數(shù)時(shí)多問(wèn)自己一句別人看到這個(gè)函數(shù)名和參數(shù)列表能不能猜到它是干什么的需要返回什么如果答案是否定的那就應(yīng)該調(diào)整命名或結(jié)構(gòu)。結(jié)尾踩過(guò)不少坑之后我對(duì)函數(shù)定義與調(diào)用最大的體會(huì)是基礎(chǔ)語(yǔ)法只是入門(mén)的第一層臺(tái)階真正決定代碼質(zhì)量的是設(shè)計(jì)習(xí)慣。每當(dāng)我看到一個(gè)冗長(zhǎng)的腳本里隨手寫(xiě)的重復(fù)邏輯就會(huì)把它們提取成函數(shù)這個(gè)過(guò)程帶來(lái)的不只是代碼行數(shù)的縮減更是思路的清晰化。讓每個(gè)函數(shù)只做一件事、通過(guò)名稱(chēng)表達(dá)意圖、用參數(shù)和返回值保持邊界清晰這些習(xí)慣一旦養(yǎng)成寫(xiě)出來(lái)的代碼質(zhì)量會(huì)有非常明顯的提升。還有一個(gè)一直提醒自己的技巧寫(xiě)完函數(shù)后嘗試用一句自然語(yǔ)言描述它做什么如果這句話太長(zhǎng)或者用了“然后”“并且”這類(lèi)連接詞說(shuō)明函數(shù)職責(zé)不單一可以繼續(xù)拆分。這樣的簡(jiǎn)單自查往往能在項(xiàng)目初期就避免很多維護(hù)階段的問(wèn)題。