2016-06-09 49 views
3

問題: 我想知道遞歸地將函數應用於對象中的字符串值而不事先知道它的架構的最pythonic方法嗎?最好以足夠通用的方式使其成爲其他類型操作的可重用組件。遞歸地將函數應用於字符串值的大多數pythonic方式

上下文: 我處理JSON字符串作爲從API請求輸入,使用json.loads()加載它,我想之前或之後的任何的去掉所有空白施加驗證之前對象中的字符串。我更喜歡這個代碼是自適應的,以便模式中的變化不會破壞它。

目前的解決方案:

def strip(obj): 
    return obj.strip() 

def recurse_into(obj, baseaction, basetype=str): 
    if isinstance(obj, basetype): 
     return baseaction(obj) 
    elif isinstance(obj, list): 
     return [recurse_into(o, baseaction, basetype) for o in obj] 
    elif isinstance(obj, tuple): 
     return tuple(recurse_into(o, baseaction, basetype) for o in obj) 
    elif isinstance(obj, dict): 
     return dict((k, recurse_into(v, baseaction, basetype)) 
        for (k, v) in obj.items()) 
    else: 
     return obj 

def generate_recurse(baseaction, basetype=str): 
    def f(obj): 
     return recurse_into(obj, baseaction, basetype) 
    return f 

def recursive_strip_whitespace(obj): 
    clean_whitespace = generate_recurse(strip) 
    return clean_whitespace(obj) 

問題與當前的解決方案: 它看起來非常簡潔,這是很難理解正在發生的事情對誰沒有寫它的人,我真的希望有更可讀的方法來做到這一點。或者,這是否真的是最好的?

+0

老實說,這段代碼對我來說看起來很乾淨優雅。如果難以理解,也許更多評論會有所幫助? – recursive

+0

爲什麼不只是'return recurse_into(obj,strip)',而不是「生成」遞歸函數,並將其保存到變量中? – bozdoz

+0

爲什麼不只是使用一個簡單的正則表達式? –

回答

0

我的建議是削減一些冗餘代碼:

def strip(obj): 
    return obj.strip() 

def recurse_into(obj, baseaction, basetype=str): 
    if isinstance(obj, basetype): 
     return baseaction(obj) 
    elif isinstance(obj, list): 
     return [recurse_into(o, baseaction, basetype) for o in obj] 
    elif isinstance(obj, tuple): 
     return tuple(recurse_into(o, baseaction, basetype) for o in obj) 
    elif isinstance(obj, dict): 
     return dict((k, recurse_into(v, baseaction, basetype)) 
        for (k, v) in obj.items()) 
    return obj 

def recursive_strip_whitespace(obj): 
    return recurse_into(obj, strip) 
+0

我也認爲'basetype'關鍵字可能會很笨拙,因爲它留下了用'list'作爲'basetype'的函數的空間,這意味着它可以檢查obj是否是列表的兩倍。 – bozdoz

0

同樣的方法「反轉」將是獨立的功能分割的情況,並將它們映射出來。它不那麼容易理解,但可能看起來更具可讀性。

def strip_obj(obj): 
    return obj.strip() 
def strip_tuple(tuple): 
    return tuple(recurse(obj) for obj in tupl) 
... 
def recurse(root): 
    actions = {basetype: strip_obj, 
       tuple: strip_tuple, 
       ...} 
    return actions[type(root)](root) 

注意,對於iterables你可以「去功能性」與map,但我個人覺得過於密集。同樣,您可以通過在actions值中使用lambda來獲得meta-juju,但它對於可讀性來說也不會太好。