摘要:變量用的好或不好,和代碼質(zhì)量有著非常重要的聯(lián)系。簡而言之,匈牙利命名法就是把變量的類型縮寫,放到變量名的最前面。很多情況下,使用匈牙利命名法是個不錯的主意,因為它可以改善你的代碼可讀性,尤其在那些變量眾多同一類型多次出現(xiàn)時。
歡迎大家前往騰訊云+社區(qū),獲取更多騰訊海量技術(shù)實踐干貨哦~
本文由鵝廠優(yōu)文發(fā)表于云+社區(qū)專欄『Python 工匠』是什么?作者:朱雷 | 騰訊IEG高級工程師
我一直覺得編程某種意義上是一門『手藝』,因為優(yōu)雅而高效的代碼,就如同完美的手工藝品一樣讓人賞心悅目。
在雕琢代碼的過程中,有大工程:比如應該用什么架構(gòu)、哪種設計模式。也有更多的小細節(jié),比如何時使用異常(Exceptions)、或怎么給變量起名。那些真正優(yōu)秀的代碼,正是由無數(shù)優(yōu)秀的細節(jié)造就的。
『Python 工匠』這個系列文章,是我的一次小小嘗試。它專注于分享 Python 編程中的一些偏『小』的東西。希望能夠幫到每一位編程路上的匠人。
變量和代碼質(zhì)量作為『Python 工匠』系列文章的第一篇,我想先談談 『變量(Variables)』。因為如何定義和使用變量,一直都是學習任何一門編程語言最先要掌握的技能之一。
變量用的好或不好,和代碼質(zhì)量有著非常重要的聯(lián)系。在關(guān)于變量的諸多問題中,為變量起一個好名字尤其重要。
如何為變量起名在計算機科學領(lǐng)域,有一句著名的格言(俏皮話):
There are only two hard things in Computer Science: cache invalidation and naming things. 在計算機科學領(lǐng)域只有兩件難事:緩存過期 和 給東西起名字 -- Phil Karlton
第一個『緩存過期問題』的難度不用多說,任何用過緩存的人都會懂。至于第二個『給東西起名字』這事的難度,我也是深有體會。在我的職業(yè)生涯里,度過的作為黑暗的下午之一,就是坐在顯示器前抓耳撓腮為一個新項目起一個合適的名字。
編程時起的最多的名字,還數(shù)各種變量。給變量起一個好名字很重要,因為好的變量命名可以極大提高代碼的整體可讀性。
下面幾點,是我總結(jié)的為變量起名時,最好遵守的基本原則。
1. 變量名要有描述性,不能太寬泛在可接受的長度范圍內(nèi),變量名能把它所指向的內(nèi)容描述的越精確越好。所以,盡量不要用那些過于寬泛的詞來作為你的變量名:
BAD: day, host, cards, temp
GOOD: day_of_week, hosts_to_reboot, expired_cards
2. 變量名最好讓人能猜出類型所有學習 Python 的人都知道,Python 是一門動態(tài)類型語言,它(至少在 PEP 484 出現(xiàn)前)沒有變量類型聲明。所以當你看到一個變量時,除了通過上下文猜測,沒法輕易知道它是什么類型。
不過,人們對于變量名和變量類型的關(guān)系,通常會有一些直覺上的約定,我把它們總結(jié)在了下面。
『什么樣的名字會被當成 bool 類型?』布爾類型變量的最大特點是:它只存在兩個可能的值『是』 或 『不是』。所以,用 is、has 等非黑即白的詞修飾的變量名,會是個不錯的選擇。原則就是:讓讀到變量名的人覺得這個變量只會有『是』或『不是』兩種值。
下面是幾個不錯的示例:
is_superuser:『是否超級用戶』,只會有兩種值:是/不是
has_error:『有沒有錯誤』,只會有兩種值:有/沒有
allow_vip:『是否允許 VIP』,只會有兩種值:允許/不允許
use_msgpack:『是否使用 msgpack』,只會有兩種值:使用/不使用
debug:『是否開啟調(diào)試模式』,被當做 bool 主要是因為約定俗成
『什么樣的名字會被當成 int/float 類型?』人們看到和數(shù)字相關(guān)的名字,都會默認他們是 int/float 類型,下面這些是比較常見的:
釋義為數(shù)字的所有單詞,比如:port(端口號)、age(年齡)、radius(半徑) 等等
使用 _id 結(jié)尾的單詞,比如:user_id、host_id
使用 length/count 開頭或者結(jié)尾的單詞,比如: length_of_username、max_length、users_count
注意:不要使用普通的復數(shù)來表示一個 int 類型變量,比如 apples、trips,最好用 number_of_apples、trips_count 來替代。
其他類型對于 str、list、tuple、dict 這些復雜類型,很難有一個統(tǒng)一的規(guī)則讓我們可以通過名字去猜測變量類型。比如 headers,既可能是一個頭信息列表,也可能是包含頭信息的 dict。
對于這些類型的變量名,最推薦的方式,就是編寫規(guī)范的文檔,在函數(shù)和方法的 document string 中,使用 sphinx 格式(Python 官方文檔使用的文檔工具)來標注所有變量的類型。
3. 適當使用『匈牙利命名法』第一次知道『匈牙利命名法』,是在 Joel on Software 的一篇博文中。簡而言之,匈牙利命名法就是把變量的『類型』縮寫,放到變量名的最前面。
關(guān)鍵在于,這里說的變量『類型』,并非指傳統(tǒng)意義上的 int/str/list 這種類型,而是指那些和你的代碼業(yè)務邏輯相關(guān)的類型。
比如,在你的代碼中有兩個變量:students 和 teachers,他們指向的內(nèi)容都是一個包含 Person 對象的 list 。使用『匈牙利命名法』后,可以把這兩個名字改寫成這樣:
students -> pl_students teachers -> pl_teachers
其中 pl 是 person list 的首字母縮寫。當變量名被加上前綴后,如果你看到以 pl_ 打頭的變量,就能知道它所指向的值類型了。
很多情況下,使用『匈牙利命名法』是個不錯的主意,因為它可以改善你的代碼可讀性,尤其在那些變量眾多、同一類型多次出現(xiàn)時。注意不要濫用就好。
4. 變量名盡量短,但是絕對不要太短在前面,我們提到要讓變量名有描述性。如果不給這條原則加上任何限制,那么你很有可能寫出這種描述性極強的變量名:how_much_points_need_for_level2。如果代碼中充斥著這種過長的變量名,對于代碼可讀性來說是個災難。
一個好的變量名,長度應該控制在 兩到三個單詞左右。比如上面的名字,可以縮寫為 points_level2。
絕大多數(shù)情況下,都應該避免使用那些只有一兩個字母的短名字,比如數(shù)組索引三劍客 i、j、k,用有明確含義的名字,比如 persion_index 來代替它們總是會更好一些。
使用短名字的例外情況有時,上面的原則也存在一些例外。當一些意義明確但是較長的變量名重復出現(xiàn)時,為了讓代碼更簡潔,使用短名字縮寫是完全可以的。但是為了降低理解成本,同一段代碼內(nèi)最好不要使用太多這種短名字。
比如在 Python 中導入模塊時,就會經(jīng)常用到短名字作為別名,像 Django i18n 翻譯時常用的 gettext 方法通常會被縮寫成 _ 來使用(from django.utils.translation import ugettext as _)
5. 其他注意事項其他一些給變量命名的注意事項:
同一段代碼內(nèi)不要使用過于相似的變量名,比如同時出現(xiàn) users、users1、 user3 這種序列
不要使用帶否定含義的變量名,用 is_special 代替 is_not_normal
更好的使用變量前面講了如何為變量取一個好名字,下面我們談談在日常使用變量時,應該注意的一些小細節(jié)。
1. 保持一致性如果你在一個方法內(nèi)里面把圖片變量叫做 photo,在其他的地方就不要把它改成 image,這樣只會讓代碼的閱讀者困惑:『image 和 photo 到底是不是同一個東西?』
另外,雖然 Python 是動態(tài)類型語言,但那也不意味著你可以用同一個變量名一會表示 str 類型,過會又換成 list。同一個變量名指代的變量類型,也需要保持一致性。
2. 盡量不要用 globals()/locals()也許你第一次發(fā)現(xiàn) globals()/locals() 這對內(nèi)建函數(shù)時很興奮,迫不及待的寫下下面這種極端『簡潔』的代碼:
def render(request, user_id, trip_id): user = User.objects.get(id=user_id) trip = get_object_or_404(Trip, pk=trip_id) is_suggested = is_suggested(user, trip) # 利用 locals() 節(jié)約了三行代碼,我是個天才! return render(request, "trip.html", locals())
千萬不要這么做,這樣只會讓讀到這段代碼的人(包括三個月后的你自己)痛恨你,因為他需要記住這個函數(shù)內(nèi)定義的所有變量(想想這個函數(shù)增長到兩百行會怎么樣?),更別提 locals() 還會把一些不必要的變量傳遞出去。
更何況, The Zen of Python(Python 之禪) 說的清清楚楚:Explicit is better than implicit.(顯式優(yōu)于隱式)。所以,還是老老實實把代碼寫成這樣吧:
return render(request, "trip.html", { "user": user, "trip": trip, "is_suggested": is_suggested })3. 變量定義盡量靠近使用
這個原則屬于老生常談了。很多人(包括我)在剛開始學習編程時,會有一個習慣。就是把所有的變量定義寫在一起,放在函數(shù)或方法的最前面。
def generate_trip_png(trip): path = [] markers = [] photo_markers = [] text_markers = [] marker_count = 0 point_count = 0 ... ...
這樣做只會讓你的代碼『看上去很整潔』,但是對提高代碼可讀性沒有任何幫助。
更好的做法是,讓變量定義盡量靠近使用。那樣當你閱讀代碼時,可以更好的理解代碼的邏輯,而不是費勁的去想這個變量到底是什么、哪里定義的?
4. 合理使用 namedtuple/dict 來讓函數(shù)返回多個值Python 的函數(shù)可以返回多個值:
def latlon_to_address(lat, lon): return country, province, city # 利用多返回值一次解包定義多個變量 country, province, city = latlon_to_address(lat, lon)
但是,這樣的用法會產(chǎn)生一個小問題:如果某一天, latlon_to_address 函數(shù)需要返回『城區(qū)(District)』時怎么辦?
如果是上面這種寫法,你需要找到所有調(diào)用 latlon_to_address 的地方,補上多出來的這個變量,否則 ValueError: too many values to unpack 就會找上你:
country, province, city, district = latlon_to_address(lat, lon) # 或者使用 _ 忽略多出來的返回值 country, province, city, _ = latlon_to_address(lat, lon)
對于這種可能變動的多返回值函數(shù),使用 namedtuple/dict 會更方便一些。當你新增返回值時,不會對之前的函數(shù)調(diào)用產(chǎn)生任何破壞性的影響:
# 1. 使用 dict def latlon_to_address(lat, lon): return { "country": country, "province": province, "city": city } addr_dict = latlon_to_address(lat, lon) # 2. 使用 namedtuple from collections import namedtuple Address = namedtuple("Address", ["country", "province", "city"]) def latlon_to_address(lat, lon): return Address( country=country, province=province, city=city ) addr = latlon_to_address(lat, lon)
不過這樣做也有壞處,因為代碼對變更的兼容性雖然變好了,但是你不能繼續(xù)用之前 x, y = f() 的方式一次解包定義多個變量了。取舍在于你自己。
5. 控制單個函數(shù)內(nèi)的變量數(shù)量人腦的能力是有限的,研究表明,人類的短期記憶只能同時記住不超過十個名字。所以,當你的某個函數(shù)過長(一般來說,超過一屏的的函數(shù)就會被認為有點過長了),包含了太多變量時。請及時把它拆分為多個小函數(shù)吧。
6. 及時刪掉那些沒用的變量這條原則非常簡單,也很容易做到。但是如果沒有遵守,那它對你的代碼質(zhì)量的打擊是毀滅級的。會讓閱讀你代碼的人有一種被愚弄的感覺。
def fancy_func(): # 讀者心理:嗯,這里定義了一個 fancy_vars fancy_vars = get_fancy() ... ...(一大堆代碼過后) # 讀者心理:這里就結(jié)束了?之前的 fancy_vars 去哪了?被貓吃了嗎? return result
所以,請打開 IDE 的智能提示,及時清理掉那些定義了但是沒有使用的變量吧。
7. 能不定義變量就不定義有時候,我們定義變量時的心理活動是這樣的:『嗯,這個值未來說不定會修改/二次使用』,讓我們先把它定義成變量吧!
def get_best_trip_by_user_id(user_id): user = get_user(user_id) trip = get_best_trip(user_id) result = { "user": user, "trip": trip } return result
其實,你所想的『未來』永遠不會來,這段代碼里的三個臨時變量完全可以去掉,變成這樣:
def get_best_trip_by_user_id(user_id): return { "user": get_user(user_id), "trip": get_best_trip(user_id) }
沒有必要為了那些可能出現(xiàn)的變動,犧牲代碼當前的可讀性。如果以后有定義變量的需求,那就以后再加吧。
結(jié)語碎碎念了一大堆,不知道有多少人能夠堅持到最后。變量作為程序語言的重要組成部分,值得我們在定義和使用它時,多花一丁點時間思考一下,那樣會讓你的代碼變得更優(yōu)秀。
這是『Python 工匠』系列文章的第一篇,不知道看完文章的你,有沒有什么想吐槽的?請留言告訴我吧。
問答
如何從變量名中獲取字符串?
相關(guān)閱讀
鵝廠優(yōu)文 | ReactJS一點通
開發(fā)效率太低?您可能沒看這篇文章
用CSS畫小豬佩奇,你就是下一個社會人!
【每日課程推薦】機器學習實戰(zhàn)!快速入門在線廣告業(yè)務及CTR相應知識
此文已由作者授權(quán)騰訊云+社區(qū)發(fā)布,更多原文請點擊
搜索關(guān)注公眾號「云加社區(qū)」,第一時間獲取技術(shù)干貨,關(guān)注后回復1024 送你一份技術(shù)課程大禮包!
海量技術(shù)實踐經(jīng)驗,盡在云加社區(qū)!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/42544.html
摘要:系列文章工匠善用變量改善代碼質(zhì)量序言編寫條件分支代碼是編碼過程中不可或缺的一部分。而進行條件分支判斷時用到的也是這個值重點來了,雖然所有用戶類實例的布爾值都是真。 歡迎大家前往騰訊云+社區(qū),獲取更多騰訊海量技術(shù)實踐干貨哦~ 本文由鵝廠優(yōu)文發(fā)表于云+社區(qū)專欄 作者:朱雷 | 騰訊IEG高級工程師 『Python 工匠』是什么? 我一直覺得編程某種意義是一門『手藝』,因為優(yōu)雅而高效的代碼...
摘要:月日,志高智能云體驗館開館盛典在佛山市南海區(qū)海八路金融公園珠三角工匠精神展示館隆重舉行。作為該展示館首家開館企業(yè),志高智能云體驗館不僅展示了佛山脊梁企業(yè)的品牌魅力,同時也將成為廣東制造工匠精神的全新地標。3月5日,志高智能云+體驗館開館盛典在佛山市南海區(qū)海八路金融公園珠三角工匠精神展示館隆重舉行。作為該展示館首家開館企業(yè),志高智能云+體驗館不僅展示了佛山脊梁企業(yè)的品牌魅力,同時也將成為廣東制...
摘要:效率專精系列善用統(tǒng)一描述語言提升開發(fā)效率分鐘搞定環(huán)境配置與使用考慮到篇幅較長的文檔反復修改的情況,要快速找到修改點比較困難。 之前零零散散寫了幾篇文章,主要是實際開發(fā)過程中一些效率痛點和相應的改善方法。今天抽空溫故知新,把之前的內(nèi)容串起來,做了個小總結(jié),即《效率專精系列》小系列的總集篇。 回顧項目開發(fā)流程 開發(fā)一個新項目時,開發(fā)流程大概分成以下幾步: 設計方案,并落地成設計文檔 設計...
閱讀 3400·2023-04-26 02:09
閱讀 2716·2021-11-24 09:39
閱讀 3368·2021-11-16 11:52
閱讀 3677·2021-10-26 09:50
閱讀 2835·2021-10-08 10:05
閱讀 2520·2021-09-22 15:25
閱讀 3360·2019-08-30 13:14
閱讀 984·2019-08-29 17:06