2014-02-11 31 views
2

我正在寫一個數據分析程序,涉及很多步驟和大量數據集。有時候我想在路上保存鹹菜,有時候不會。我將稱這些節省「檢查站」。格式化如果嘗試除了其他代碼塊

如果pickle文件是可讀的,並且全局變量PICKLETrue,我可以跳過一些分析步驟。擺出代碼的愚蠢,但冗長的方法是這樣的:

if PICKLE: 
    try: 
     with open('pickle1.pkl', 'rb') as f: 
      data1 = pickle.load(f) 
    except: 
     # do things to generate data1 
     temp = step1() 
     data1 = step2(temp) 

     with open('pickle1.pkl', 'wb') as f: 
      pickle.dump(data1, f) 
else: 
    # do things to generate data1 
    temp = step1() 
    data1 = step2(temp) 

這是許多在我的分析只是一個「關卡」,並獲得這些「關卡」,一般需要的不僅僅是兩個步驟多。因此,將上面的代碼進行佈局會產生大量重複的代碼。

我可以把事情功能略有改善的事情,但要強調的醜陋,我將展示2個關卡:

def generateData1(): 
    # do things 
    return data1 

def generateData2(): 
    # do things 
    return data2 

if PICKLE: 
    try: 
     with open('pickle1.pkl', 'rb') as f: 
      data1 = pickle.load(f) 
    except: 
     data1 = generateData1() 
     with open('pickle1.pkl', 'wb') as f: 
      pickle.dump(data1, f) 
else: 
    data1 = generateData1() 

if PICKLE: 
    try: 
     with open('pickle2.pkl', 'rb') as f: 
      data2 = pickle.load(f) 
    except: 
     data2 = generateData2() 
     with open('pickle2.pkl', 'wb') as f: 
      pickle.dump(data2, f) 
else: 
    data2 = generateData2() 

現在更少的代碼重複每一個「關卡」,但一些事情,這是非常醜陋的,並且通過頂部的所有功能,以及底部的所有流控制和檢查點結構代碼,閱讀代碼需要大量的跳躍和跳躍。此外,這些示例中的所有代碼都會針對我要創建的每個檢查點重複執行,並且它們都具有完全相同的結構。

我不禁想起有一個優雅的解決方案,用最少量的重複代碼,仍然大部分是可讀的。

+0

一個小小的改進:如果你不改變兩個if語句之間的'PICKLE'的值,那麼你可以合併這兩個塊並只檢查一次'PICKLE'。 – 2rs2ts

回答

1

如何與裝飾:

import os 
import pickle 
import functools 

PICKLE = False 
PICKLE_PATH = '/tmp' 

def checkpoint(f): 

    if not PICKLE: 
     return f 

    save_path = os.path.join(PICKLE_PATH, '%s.pickle' % f.__name__) 

    @functools.wraps(f) 
    def wrapper(*args, **kwargs): 
     if os.path.exists(save_path): 
      with open(save_path, 'rb') as f: 
       return pickle.load(f) 

     rv = f(*args, **kwargs) 
     with open(save_path, 'wb') as f: 
      pickle.dump(rv, f) 

     return rv 

    return wrapper 

用法:

@checkpoint 
def step1(): 
    return do_stuff_here() 


def intermediate_step(): 
    return some_operation(step1()) 

@checkpoint 
def step2(): 
    return do_stuff_with(intermediate_step()) 

# ... and so on 
5

爲什麼不把它進一步提取到函數中以避免所有的重複代碼?

def pickle_function(pickle_filename, data_function): 
    with open(pickle_filename, 'wb') as f: 
     try: 
      data = pickle.load(f) 
     except: 
      data = data_function() 
      pickle.dump(data, f) 

if PICKLE: 
    pickle_function('pickle1.pkl', generateData1) 

# Some intermediate logic before next 'checkpoint' 

if PICKLE: 
    pickle_function('pickle2.pkl', generateData2) 

而且,我不知道打開文件的時候,所以你可能有,如果該文件可能不存在重組什麼Exception你趕上。捕獲特定的例外(例如except FileNotFoundError:)總是一個好主意,以便任何意外的行爲都會大聲提出。

0

你也需要用while語法,而不是重複if/else小號擺脫代碼重複了。

因此,作爲一個非常基本的示例,不一定打算告訴您工作流程,您可以使用一個函數來處理有關數據。

def change_data(previousdata, iteration): 
    if iteration == 0: 
     ##some change 
     return new_value 
    elif iteration == 1: 
     ##some other change 
     return new_value 
    … 
    elif iteration = total_needed ##however many different tests there are 
     indicate_doneness() ##whatever this means for you 

你有那些建議'從泡菜載入,或創建數據並轉儲它'功能。

def pickle_or_dont(args): 
    try: ##the suggested code from other answers 

然後設置一個while循環來跟蹤已完成了多少次迭代以及您處於哪個「階段」。這消除了您重複代碼的需要。

total_needed = 7 ##or however many 
data_generated = 0 
while data_generated < total_needed: 
    my_data = change_data(my_data, data_generated) 
    pickle_or_dont(my_data) 
    data_generated += 1 

我你打算操作順序的意義可能不正確,你就知道比我好,但我認爲一個while循環將讓你重複的代碼。

相關問題