2013-08-28 71 views
4

我正在學習Python,並試圖找出構造代碼的最佳方式。Python代碼/函數佈局

可以說我有一個很長的功能,並且想把它分解成更小的功能。在C中,我會讓它成爲頂層的「靜態」函數(因爲這是唯一的功能級別)。我也可能會將其聲明並將其放在使用它的現在縮短的函數之後。

現在用於Python。在Python中,我可以選擇創建嵌套函數。由於這個新的「內部」函數實際上只是爲了可讀性目的而拆分的較大函數的一部分,並且僅由它使用,它聽起來應該是嵌套函數,但在父函數內部具有此函數會導致整個函數仍然很長,因爲沒有代碼實際上被移出它!特別是由於函數在被調用之前必須被完全編碼,這意味着在這個僞長函數結束時,實際的短函數將一路下降,從而使可讀性變得糟糕!

什麼被認爲是這樣的情況良好的做法?

+1

你想留的功能,還是會在OOP編程考慮? – tim

+1

請參見[在python中定義私有模塊函數](http://stackoverflow.com/questions/1547145/defining-private-module-functions-in-python)。 – falsetru

+0

我認爲最好將您的Python編程看作一組名稱空間和作用域。使用類,模塊和包作爲將某些類型的功能和行爲(方法)綁定(封裝)給某些給定類型(類)的實例的方式。嵌套應該謹慎使用,只能用於範圍界定或避免命名空間衝突。 –

回答

2

如何將較小的函數放在自己的文件中並將其導入到主函數中?你會碰到這樣的:

def main_func(): 
    from impl import a, b, c 

    a() 
    b() 
    c() 

我認爲這種做法會導致高可讀性:你看到那裏的小功能來自於如果你想看看他們,導入它們是一個班輪,和主要功能的實現是直接可見的。通過選擇適當的文件名/位置,您還可以告訴用戶這些功能不適用於main_func以外的用途(無論如何,您都沒有真正的隱藏信息)。

順便說一句:這個問題沒有一個正確的答案。

2

據我所知,Python中內部函數的主要優點是它們繼承了封閉函數的作用域。因此,如果您需要訪問主函數範圍內的變量(例如參數或局部變量),則需要使用內部函數。否則,做任何你喜歡的和/或找到最可讀的。

編輯:this answer了。

0

好的做法是保持cycomatic complexity低。這實際上意味着將您的長期功能分解爲許多較小的功能。

的複雜性是由如果數來測量,而,這樣做,因爲,:, 接球,開關,case語句,和運營商& &和|| (加一) 構造函數的主體,方法,靜態初始值設定項或實例 初始值設定項。它是通過源的最小可能路徑數 的度量,因此是所需測試的數量。 一般認爲1-4是好的,5-7好,8-10考慮重新考慮因子, 和11+重新考慮因素吧!

我建議採納來自Sonar的代碼質量分析工具的建議。重構此類代碼的一個好方法是使用TDD。首先編寫單元測試以覆蓋當前函數的所有執行路徑。之後,您可以重新安心,單元測試將保證您不會破壞任何東西。

如果另一方面你的長函數只是很長,但其他方面已經具有較低的圈複雜度,那麼我認爲函數是否嵌套無關緊要。

+1

您提出了一些有趣的觀點,但問題不在於何時重構或如何斷言質量。問題只是詢問如何在特定情況下構建或佈置代碼。 – flornquake

+0

@flornquake你是對的。我回頭看看*症狀*並提出治療*問題*。告訴他嵌套與否的功能將是一個痛苦的殺手,而不是我給他的治療。有時候,儘管並非總是如此,但你可以做得比從字面上理解問題好得多。他描述的長期功能是製作中的恐怖故事,以及定時炸彈。他越早做點事情對他越好。嵌套函數的問題將在這個過程中蒸發。 – janos

+0

在我看來,OP已經知道何時重構以及如何分解函數。他們想知道的是將重構時得到的較小函數放到哪裏。 – flornquake

2

所以我能理解的是,你有很長的功能,如:

def long_func(blah, foo, *args): 
    ... 
... 
my_val = long_func(foo, blah, a, b, c) 

您所做的一切是:

def long_func(blah, foo, *args): 
    def short_func1(): 
     ... 
    def short_func2(): 
     ... 
    ... 
    short_func1() 
    short_func2() 
    ... 
... 
my_val = long_func(foo, blah, a, b, c) 

你有很多更多的選擇,我將列出二:

  1. 它做成一個類

    class SomeName(object): 
        def __init__(self, blah, foo, *args): 
         self.blah = blah 
         self.foo = foo 
         self.args = args 
         self.result = None # Might keep this for returning values or see (2) 
    
        def short_func1(self): 
         ... 
        def short_func2(self): 
         ... 
        def run(self): # name it as you like! 
         self.short_func1() 
         self.short_func2() 
         return self.result # (2) or return the last call, on you 
    ... 
    my_val = SomeName(foo, blah, a, b, c).run() 
    
  2. 製作另一個模塊並將short_funcs放入其中。就像flyx所建議的那樣。

    def long_func(foo, blah, *args): 
        from my_module import short_func1, short_func2 
    
        short_func1(foo) 
        short_func2(blah)