2014-05-22 125 views
1

我對python(2.7)很陌生,並且對於什麼是Pythonic最有效的方法有疑問。我的代碼(A類的一部分)貌似這個(有點天真版):Python風格:嵌套與額外功能

def calc_pump_height(self): 
    for i in range(len(self.primary_)): 
     for j in range(len(self.primary_)): 
      if self.connections_[i][j].sub_kind_ in [1,4]: 
       self.calc_spec_pump_height(i,j) 

def calc_spec_pump_height(self,i,j): 
    pass 

(顯然通行證將被別的東西所取代,操縱這個類的對象的屬性,而不會產生一個返回值)我想問我應該怎麼做:我可以避免第二個函數,並將額外的代碼直接寫入第一個函數,擺脫一個函數(簡單比複雜更好),但創建一個重度同時嵌套函數(Flat比嵌套更好)。

我還可以建立某種形式的名單理解,以避免使用雙迴路,例如:

def calc_pump_height(self): 
    ra = range(len(self.primary_)) 
    [self.calc_spec_pump_height(i,j) for i,j in zip(ra, ra)] 

(我不得不如果條件進入第二個功能;這也將創建一個空 - 但我不在乎這一點,因爲calc_spec_pump_height應該操縱對象,而不是返回一些有用的東西)

實質上:我遍歷2D列表,測試每個對象的某個特徵,然後用這個對象做些事情。

以上哪種方法是'最好的'?還是有另一種我失蹤的方式?

+0

恕我直言,第二種方式看起來很乾淨,但它可能只是我... – Dair

+0

出於好奇,爲什麼你的一些屬性的結束與_?在Python中,如果你試圖指出某個類是私有的,那麼你通常在開始時加一個下劃線,而不是結尾。 – Ben

+0

@Ben:你說得對,現在我知道了。這實際上是我剛開始使用Python時寫的一段代碼的一部分,我正在重寫它,但沒有重新命名變量(最初的想法是區分本地變量和類變量)。在Python中這是(除了違反標準)冗餘由於'自我'。在我的其他項目(例如:編程微控制器)它不是。) – cfrei89

回答

2

函數/方法的關鍵在於它們應該做一件事。

calc_pump_height實現了兩件事:它在2D列表中查找與某些條件匹配的元素,然後計算每個元素的值。其目的是將其他兩個操作組合起來,如果這對於對象的公共API來說是有意義的,但它不適用於實現或兩者兼而有之。

  • 查找符合條件的元素是一個離散的步驟;這應該是一個功能。
  • 計算你的價值顯然是一個不連續的步驟;這應該是一個功能。

我將實現元素匹配器作爲(私有)生成器,它將測試條件作爲參數,並生成所有匹配的元素。它只是數據結構的迭代器,被邏輯測試所掩蓋。您可以將其封裝在名爲get_1_4_subkinds()的指定公用方法中,或者在您的域中更有意義的方法。該代碼概括並賦予您未來實現其他條件的靈活性。另外,你的i和j是緊密結合的,所以把它們作爲一個概念傳遞是有意義的。那麼你的代碼變成:

def calc_pump_height(self): 
    for subkind_indices in self.get_1_4_subkinds(): 
     self.calc_pump_spec_height(subkind_indices) 
+0

有趣的一點,我沒有這樣認爲,但它肯定會在以後得到方便,謝謝!此外,您還有一點意見認爲將它分開是有道理的,因爲這兩部分分開進行。 – cfrei89

0

你誤解了「簡約」:

直接寫額外的代碼進入第一功能,擺脫一個功能(簡單比複雜好)

這並不簡單。將複雜序列分解爲離散的,集中的功能增加了的簡單性。

有鑑於此,我會說是的,你應該更喜歡calc_spec_pump_height作爲一個單獨的功能。

0

您可以通過使用itertools.product產生在同一時間(itertools.product(range(len(self.primary_)), repeat=2),你在你的第二個版本中使用的zip將無法​​正常工作,它只會您ij值消除你的第一個功能一級嵌套產生相同的對,0,01,12,2

至於整體設計,你不應該,如果你不關心從你調用該函數的返回值,使用列表理解。使用顯式循環時,它是你想要的循環(而不是一個計算值列表)

如果在calc_spec_pump_height中存在非常重要的代碼量,則將其作爲單獨的方法進行使用是非常有意義的。如果它是一個或兩個班輪,那麼可以在calc_pump_height內聯行,但是該方法的循環和條件測試可能已經足夠複雜以足以證明分解算法的內部部分。

當你的編輯器中的一個屏幕太長時,你應該考慮分割一個大功能。這是關於我們可以同時記住多少細節(變量名等)的限制。另一方面,通過分解每一個小問題,你不應該浪費時間(無論是你自己的編程時間還是運行時的函數調用開銷)。如果您在多個地方使用該功能,或者無法一次性保留頭部整個功能的詳細信息,則將該功能的一部分作爲功能的一部分。

因此,除了itertools.product的(邊際)改進之外,由於您提供的有關calc_spec_pump_height將執行的操作的信息有限,因此我認爲您的代碼已經達到了它所能達到的最佳狀態!

+0

感謝您指出我的錯誤,並提供一些'基準'的長度功能等 – cfrei89