分析一套源代碼的代碼規範和風格並討論如何改進優化代碼

  個人工程實踐選題是《針對領域知識的中文知識圖譜自動化構建》,我將選取用於知識圖譜的分佈式表示計算框架OpenKE,代碼目錄以下圖所示:python

                              

 

  咱們能夠看到源代碼目錄中包括多個文件夾,其中主要爲:git

base:基礎操做代碼,包括文件讀寫,獲取樣本數,設置工做目錄等github

benchmarks:一些用於評測算法性能的數據集算法

config:設置運行所需的參數app

examples:將本框架運用於不一樣數據集上的代碼示例框架

models:本框架中包含的一些算法模型分佈式

release:由base打包獲得的動態庫ide

res:程序運行獲得的一些結果函數

  除此以外咱們能夠看到在主目錄裏還有一些文件,包括許可證,框架使用樣例,編譯文件,說明文件等。能夠看出整個工程的組織比較清晰,文件夾命名比較規範。性能

  下面咱們來看一段代碼:

 1 #coding:utf-8
 2 import numpy as np
 3 import tensorflow as tf
 4 from .Model import Model
 5 
 6 if tf.__version__ > '0.12.1':
 7     matmul_func = tf.matmul
 8 else:
 9     matmul_func = tf.batch_matmul
10 
11 class TransR(Model):
12     r'''
13     TransR first projects entities from entity space to corresponding relation space 
14     and then builds translations between projected entities. 
15     '''
16     def _transfer(self, transfer_matrix, embeddings):
17         return matmul_func(embeddings, transfer_matrix)
18 
19     def _calc(self, h, t, r):
20         h = tf.nn.l2_normalize(h, -1)
21         t = tf.nn.l2_normalize(t, -1)
22         r = tf.nn.l2_normalize(r, -1)
23         return abs(h + r - t)
24 
25     def embedding_def(self):
26         #Obtaining the initial configuration of the model
27         config = self.get_config()
28         #Defining required parameters of the model, including embeddings of entities and relations, and mapping matrices
29         self.ent_embeddings = tf.get_variable(name = "ent_embeddings", shape = [config.entTotal, config.ent_size], initializer = tf.contrib.layers.xavier_initializer(uniform = False))
30         self.rel_embeddings = tf.get_variable(name = "rel_embeddings", shape = [config.relTotal, config.rel_size], initializer = tf.contrib.layers.xavier_initializer(uniform = False))
31         self.transfer_matrix = tf.get_variable(name = "transfer_matrix", shape = [config.relTotal, config.ent_size * config.rel_size], initializer = tf.contrib.layers.xavier_initializer(uniform = False))
32         self.parameter_lists = {"ent_embeddings":self.ent_embeddings, \
33                                 "rel_embeddings":self.rel_embeddings, \
34                                 "transfer_matrix":self.transfer_matrix}
35 
36     def loss_def(self):
37         #Obtaining the initial configuration of the model
38         config = self.get_config()
39         #To get positive triples and negative triples for training
40         #The shapes of pos_h, pos_t, pos_r are (batch_size, 1)
41         #The shapes of neg_h, neg_t, neg_r are (batch_size, negative_ent + negative_rel)
42         pos_h, pos_t, pos_r = self.get_positive_instance(in_batch = True)
43         neg_h, neg_t, neg_r = self.get_negative_instance(in_batch = True)
44         #Embedding entities and relations of triples, e.g. pos_h_e, pos_t_e and pos_r_e are embeddings for positive triples
45         pos_h_e = tf.nn.embedding_lookup(self.ent_embeddings, pos_h)
46         pos_t_e = tf.nn.embedding_lookup(self.ent_embeddings, pos_t)
47         pos_r_e = tf.nn.embedding_lookup(self.rel_embeddings, pos_r)
48         neg_h_e = tf.nn.embedding_lookup(self.ent_embeddings, neg_h)
49         neg_t_e = tf.nn.embedding_lookup(self.ent_embeddings, neg_t)
50         neg_r_e = tf.nn.embedding_lookup(self.rel_embeddings, neg_r)
51         #Getting the required mapping matrices
52         pos_matrix = tf.reshape(tf.nn.embedding_lookup(self.transfer_matrix, pos_r), [-1, config.ent_size, config.rel_size])
53         #Calculating score functions for all positive triples and negative triples
54         p_h = self._transfer(pos_matrix, pos_h_e)
55         p_t = self._transfer(pos_matrix, pos_t_e)
56         p_r = pos_r_e
57         if config.negative_rel == 0:
58             n_h = self._transfer(pos_matrix, neg_h_e)
59             n_t = self._transfer(pos_matrix, neg_t_e)
60             n_r = neg_r_e
61         else:
62             neg_matrix = tf.reshape(tf.nn.embedding_lookup(self.transfer_matrix, neg_r), [-1, config.ent_size, config.rel_size])
63             n_h = self._transfer(neg_matrix, neg_h_e)
64             n_t = self._transfer(neg_matrix, neg_t_e)
65             n_r = neg_r_e
66         #The shape of _p_score is (batch_size, 1, hidden_size)
67         #The shape of _n_score is (batch_size, negative_ent + negative_rel, hidden_size)
68         _p_score = self._calc(p_h, p_t, p_r)
69         _n_score = self._calc(n_h, n_t, n_r)
70         #The shape of p_score is (batch_size, 1, 1)
71         #The shape of n_score is (batch_size, negative_ent + negative_rel, 1)
72         p_score =  tf.reduce_sum(_p_score, -1, keep_dims = True)
73         n_score =  tf.reduce_sum(_n_score, -1, keep_dims = True)
74         #Calculating loss to get what the framework will optimize
75         self.loss = tf.reduce_mean(tf.maximum(p_score - n_score + config.margin, 0))
76 
77     def predict_def(self):
78         config = self.get_config()
79         predict_h, predict_t, predict_r = self.get_predict_instance()
80         predict_h_e = tf.reshape(tf.nn.embedding_lookup(self.ent_embeddings, predict_h), [1, -1, config.ent_size])
81         predict_t_e = tf.reshape(tf.nn.embedding_lookup(self.ent_embeddings, predict_t), [1, -1, config.ent_size])
82         predict_r_e = tf.reshape(tf.nn.embedding_lookup(self.rel_embeddings, predict_r), [1, -1, config.rel_size])
83         predict_matrix = tf.reshape(tf.nn.embedding_lookup(self.transfer_matrix, predict_r[0]), [1, config.ent_size, config.rel_size])
84         h_e = tf.reshape(self._transfer(predict_matrix, predict_h_e), [-1, config.rel_size])
85         t_e = tf.reshape(self._transfer(predict_matrix, predict_t_e), [-1, config.rel_size])
86         r_e = predict_r_e
87         self.predict = tf.reduce_sum(self._calc(h_e, t_e, r_e), -1, keep_dims = True)

  咱們能夠看到這是一個類的定義,總體比較規整,變量名和函數命名都和實際意義清晰對應,而且還有必定量的英文註釋,這有助於世界各地的開發者使用和修改這個代碼框架。

  從整個代碼框架的實現來看,OpenKE項目的代碼實現層次清晰,註釋明瞭,代碼中命名規範,讓閱讀者很容易理解其表明的實際含義。除此以外,代碼的縮進以及函數間空行是比較規範的,使得代碼塊之間有清楚的界限。對於一些比較長的語句可以作到合理的換行,不至於在閱讀時不能徹底顯示。

  可是代碼仍有一些不足之處:①部分代碼註釋不夠詳盡,沒有說明一些命名較簡單的變量名錶明的實際含義 ②整個項目缺少對源代碼組織以及代碼編寫理論的介紹,使得初學者不易理清代碼和理論之間的對應關係。

  下面我將列舉一些Python代碼風格規範,資料來源於谷歌開源項目風格指南

分號

不要在行尾加分號, 也不要用分號將兩條命令放在同一行。

行長度

每行不超過80個字符

例外:

  1. 長的導入模塊語句
  2. 註釋裏的URL

不要使用反斜槓鏈接行。

Python會將圓括號,中括號和花括號中的行隱式的鏈接起來 ,你能夠利用這個特色。 若是須要,你能夠在表達式外圍增長一對額外的圓括號。若是一個文本字符串在一行放不下, 可使用圓括號來實現隱式行鏈接。在註釋中,若是必要,將長的URL放在一行上。

括號

除非是用於實現行鏈接,不然不要在返回語句或條件語句中使用括號,不過在元組兩邊使用括號是能夠的。

縮進

用4個空格來縮進代碼,絕對不要用tab,也不要tab和空格混用。 對於行鏈接的狀況,你應該要麼垂直對齊換行的元素, 或者使用4空格的懸掛式縮進(這時第一行不該該有參數)。

空行

按照標準的排版規範來使用標點兩邊的空格,括號內不要有空格。不要在逗號、分號、冒號前面加空格,但應該在它們後面加(除了在行尾)。參數列表,、索引或切片的左括號前不該加空格。在二元操做符兩邊都加上一個空格,好比賦值(=), 比較(==, <, >, !=, <>, <=, >=, in, not in, is, is not), 布爾(and, or, not)。至於算術操做符兩邊的空格該如何使用, 須要你本身好好判斷。當’=’用於指示關鍵字參數或默認參數值時, 不要在其兩側使用空格。不要用空格來垂直對齊多行間的標記,由於這會成爲維護的負擔(適用於:, #, =等)。

語句

一般每一個語句應該獨佔一行,不過, 若是測試結果與測試語句在一行放得下,你也能夠將它們放在同一行。 若是是if語句, 只有在沒有else時才能這樣作。特別地, 毫不要對 try/except 這樣作, 由於try和except不能放在同一行。

命名

命名約定

  1. 所謂」內部(Internal)」表示僅模塊內可用, 或者, 在類內是保護或私有的.
  2. 用單下劃線(_)開頭表示模塊變量或函數是protected的(使用from module import *時不會包含).
  3. 用雙下劃線(__)開頭的實例變量或方法表示類內私有.
  4. 將相關的類和頂級函數放在同一個模塊裏. 不像Java, 不必限制一個類一個模塊.
  5. 對類名使用大寫字母開頭的單詞(如CapWords, 即Pascal風格), 可是模塊名應該用小寫加下劃線的方式(如lower_with_under.py). 儘管已經有不少現存的模塊使用相似於CapWords.py這樣的命名, 但如今已經不鼓勵這樣作, 由於若是模塊名碰巧和類名一致, 這會讓人困擾.

應該避免的名稱

  1. 單字符名稱, 除了計數器和迭代器.
  2. 包/模塊名中的連字符(-)
  3. 雙下劃線開頭並結尾的名稱(Python保留, 例如__init__)
相關文章
相關標籤/搜索