Python程序員的自我修養

2014年,我國發布了語言法,目的就是要規範我國語言的使用,方便大家的溝通、文化的傳承。語言有語法,程序也有語法,但程序的語法除了要過解釋器以外,剩下的就看程序員的習慣了,這裏並沒有什麼硬性的規定,主要是一些約定俗成的做法。首先是一些官方的推薦寫法,能查到的東西我也不多說,具體可以參照Python編碼規範。如果你覺得裏面的內容太難記,一時半會不能背下來,那我告訴你,千萬別背!這裏要推薦一下我用的IDE——PyCharm,相信大家一定都聽說過,其強大的功能,除了一些編程有的提示以爲,那就是把編碼規範的檢查給原生加進去了,包括命名、空格、縮進等等,如果是有強迫症的朋友,把滾動條上方的綠色方框改到變成綠色無波浪線的勾勾,那就說明你的代碼基本符合了規範。

但依然有很多規範是無法被檢測的,例如命名。鑑於大家平日生活的語言環境都是中文,所以命名也就千差萬別,好的是使用英文縮寫,但縮寫的位數不定,更有甚着,使用拼音,最不能理解的,是拼音的縮寫!還是拼音的首字母縮寫!!!還沒有註釋!!!!!雖然很多人說,好的工程師是寫文檔,又有人說,更好的工程師是寫註釋,但從本科裏,我的導師就跟我說,一段好的代碼,是不需要註釋和文檔的,“it speaks itself!”所以,我強烈推薦大家使用英文的全單詞,不要怕長,如果爲了解釋一個兩個字母的變量名你花了一段話,那樣更臃腫。英文全單詞構成的變量和方法,再加上Python本來已經非常接近自然語言的保留字,你會發現一段好的代碼就像一篇好的文章,即便是不懂編程的人,也能看懂。如果你覺得你的英文水平不行,不要怕麻煩,就算每新建一個變量,百度一遍又如何?長期下來,對提高閱讀英文文檔的能力肯定有一定幫助。

Python之所以被推崇,其中一個原因就是它的工具包很多,所以當你要做一件事情的時候,首先去看看有沒有工具包支持,但import一個module以後,別忙着用,也別忙着拷貝網上的代碼,Python是開源的,你可以先看文檔,不行直接看源碼,好的文檔或者源碼都有官方提供的例子,工具包的編寫者寫出這樣的類或者方法,肯定有他的期望的用途,按照這些官方的例子,你可以直接理解到作者的意圖,用最合適的方式去使用這個工具包。這裏舉個例子:

* Restart training from a saved graph and checkpoints.

  * Run inference from a saved graph and checkpoints.

  ```Python
  ...
  # Create a saver.
  saver = tf.train.Saver(...variables...)
  # Remember the training_op we want to run by adding it to a collection.
  tf.add_to_collection('train_op', train_op)
  sess = tf.Session()
  for step in xrange(1000000):
      sess.run(train_op)
      if step % 1000 == 0:
          # Saves checkpoint, which by default also exports a meta_graph
          # named 'my-model-global_step.meta'.
          saver.save(sess, 'my-model', global_step=step)
  ```

  Later we can continue training from this saved `meta_graph` without building
  the model from scratch.

  ```Python
  with tf.Session() as sess:
    new_saver = tf.train.import_meta_graph('my-save-dir/my-model-10000.meta')
    new_saver.restore(sess, 'my-save-dir/my-model-10000')
    # tf.get_collection() returns a list. In this example we only want the
    # first one.
    train_op = tf.get_collection('train_op')[0]
    for step in xrange(1000000):
      sess.run(train_op)
  ```

在官方的源代碼裏面,關於saver,有這樣一個例子,可以說,在無意中看到這個例子之前,我在網上看到的代碼基本沒提過collection,就算有,也只是草草帶過,大部分的代碼也只是直接使用本地變量存儲Tensor的引用,而沒有使用到collection,這使得代碼的全局性欠缺,並沒有很好地領悟到作者寫這個功能的意圖。除了collection,例子中還提到了圖的輸出和重載,這樣,我們並不需要每次都新建一系列的Tensor,當代碼訓練完後,我們在使用Checkpoint的時候直接恢復圖表就可以了,大大提高了代碼的遷移和重用性。除了Tensorflow,logging和thread模塊也有很多曲解作者意圖的代碼在網絡上廣泛傳播着,這裏便不一一展開。

當我們理解了其他作者的抽象以後,便需要開始抽象組織自己的代碼,我從來不認爲第一次編碼能夠有多規範或者多抽象,我也沒有在編碼前過多設計類圖的習慣,很多時候有了一個初步的想法,我就會寫代碼實現它。第一次的代碼基本就是一篇流水賬,然後我會看看代碼中有什麼可以重用的地方,便抽象出一個函數,當一系列的函數需要共用一些參數的時候或者有業務的單元經常需要複用或者批量新建的時候,便考慮新建一個類,然後放在另一個文件裏,當很多文件都需要共同的變量的時候,就考慮把變量放在一個配置文件。可以說,我重構代碼的時間是第一次實現功能的幾倍,每隔一段時間我都會回頭看自己的代碼。我始終都記得本科導師的那句話,“過分的設計是萬惡的根源”,因爲你的能力、工具包的能力、計算機的能力、甚至業務的需求都是不斷改變的,我們要的不是完備的設計,而是方便維護的代碼,不斷迭代。在不斷重構中,你的設計能力也會不斷增強,我總結出了一些原則,供大家參考:

1、使用工具包的時候,優先尋找工廠方法,能夠使用工廠方法獲取的實例,如果不是代碼過長的話,沒必要使用本地變量存儲,直接使用;

2、“do one thing”,當你的函數,或者循環結構裏面有太多行的時候,你就應該考慮新建一個函數來做這件事情,然後直接調用這個函數,而不是做一個臃腫的循環結構。

3、代碼中不顯式出現字符串,包括key和提示語,這點可以參照一下tensorflow.GraphKeys,裏面把常用的key都用常量存起來。然後對於提示語,可以放在配置文件中,用變量和函數讀取。這裏特別提一點,對於帶變量的提示語,建議使用“%d%s%f”這些格式符號,而不是把字符串和變量用“+”或者“,”連起來,以前一直不理解爲何要這樣使用,直到後來發現,當我們要把提示語放到配置文件的時候,使用格式符號,可以在同一條記錄裏面修改整條語句,保證語義完整,也方便做不同的語言包。

4、不要出現絕對路徑,很多時候我們的代碼都需要在win和Linux之間遷移,使用絕對路徑的時候你會需要兩份配置文件乃至兩份代碼,善用os.path這個工具。

5、只在一個類的方法中使用到的函數,即便不需要用到類屬性,也建議用靜態方法去實現,而不要放在類外面的結構裏,因爲類名也是對函數名的一種解釋,而且也便於使用者查找。

6、不是類方法共用的參數、不需要持續保存的參數,沒必要做成類屬性,減少對類屬性的依賴可以使得函數的複用性更高。

7、方法參數的順序儘量跟其出現的順序一致。

8、調用多個參數的方法的時候,儘量把參數名帶上,這樣可以避免因爲順序錯誤而引起出錯,也方便維護的人看懂代碼。

9、很多時候,你會發現勤快地輸出日誌,比你註釋你的代碼或者逐步調試有用得多。你可以考慮使用不同級別的日誌來區分正式使用和debug。

目前想到的就是這些,我覺得,個人習慣比語法重要得多,而且很多東西不是一蹴而就的,不要怕麻煩,重構你的代碼吧!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章