2017-01-02 31 views
1

我使用Python 3.5,這是我處理目前代碼:Python如何優雅地處理不同數據結構的用法?

def is_odd_number(n): 
    """states if n is an odd number""" 
    return n % 2 == 1 


def collatz_next(n): 
    """returns the successor to n in Collatz sequence""" 
    return 3*n + 1 if is_odd_number(n) else n//2 


def collatz_seq_sum(seq): 
    """returns the sum of all elements to a given Collatz sequence""" 
    return sum(seq) 


def collatz_seq(n): 
    """returns the Collatz sequence to n""" 
    l = [] 
    l.append(n) 
    current = n 
    while current != 1: 
     next_one = collatz_next(current) 
     l.append(next_one) 
     current = next_one 
    return l 


def collatz_seqs(lower_limit=1, upper_limit=10): 
    """returns Collatz sequences from lower_limit to upper_limit""" 
    return {i: collatz_seq(i) for i in range(lower_limit, upper_limit+1)} 

我認爲這類型list是最好的一個在Collat​​z序列的時候。這就是爲什麼collatz_seq返回一個列表。然而,我發現觀察連續處理多個參數n時這個特定序列是如何發展是很有趣的。這就是爲什麼我創建了collatz_seqs

我不喜歡collatz_seq_sum有一個非常簡單的原因:它只有在參數seq的類型爲list時才能正常工作。在我看來,collatz_seq_sum不是確保提供適當的實際參數的責任,在這種情況下,list由自然數組成。在我看來,致電collatz_seq_sum必須確保它提供了一個正確的參數。

我想要collatz_sum_seq可以使用單個和多個序列。 collatz_seq返回listcollatz_seqs返回dict。因此我的問題是:確保collatz_seq_sum始終爲其參數seq獲取正確數據類型的優雅方法是什麼?關於collatz_seq_sum的正確工作,我可以做些什麼?collatz_seq_sum關心其參數seq的數據類型?我的第一個想法是更改collatz_seq以使其返回dict而不是list並更改collatz_seq_sum以處理dict。但是,我不喜歡這種方法,因爲我不想在處理單個序列時使用dict

您有任何解決方案嗎?非常感謝你提前。

+0

[mypy](https://github.com/python/mypy)靜態類型檢查庫提供了[裝飾器](https://jeffknupp.com/blog/2013/11/29/improve-your- python-decorators-explained /)命名爲「重載」,它似乎允許你想要的那種多態:http://mypy.readthedocs.io/en/latest/function_overloading.html。看起來很有希望給我。 –

+0

會[functools.singledispatch](https://docs.python.org/3/library/functools.html#functools.singledispatch)有幫助嗎? – wwii

回答

0

是檢查給出的參數的類型:

from collections.abc import Mapping, Iterable 

def collatz_seq_sum(seq): 
    """returns the sum of all elements to a given Collatz sequence""" 
    if isinstance(seq, Mapping): 
     ret = {key: sum(values) for key, values in seq.items()} 
    elif isinstance(seq, Iterable): 
     ret = sum(seq) 
    else: 
     msg = "collatz_seq_sum got unexpected type: '{}'".format(type(seq)) 
     raise TypeError(msg) 
    return ret 
如果你想要一個功能不同的行爲取決於輸入這種類型

是要走的路。

+0

感謝您的輸入。這是一個很好的論據,我理解它。我只是想知道:這是唯一的方法嗎?假設您使用的腳本使用了數百個(如果不是數千個)函數。我的意思是它總是一遍又一遍:每個函數檢查其參數的類型並相應地執行操作。一遍又一遍地做同樣的事情變得非常乏味,我認爲很難閱讀和維護。 – 6q9nqBjo

+0

這是什麼類(和鴨子打字)。這是Python的哲學。 –

0

如果我理解正確,那麼您希望collatz_seq_sum可以同時使用collat​​z序列或單個collat​​z序列。在字典的情況下,您希望函數返回單個拼貼序列總和的字典。

您可以使用isinstance來檢查輸入seq是字典還是列表,並針對每種情況運行不同的代碼。下面的代碼將工作。

def collatz_seq_sum(seq): 
    """returns the sum of all elements to a given Collatz sequence""" 
    if isinstance(seq, dict): 
     return {i: sum(seqi) for i, seqi in seq.items()} 
    else: 
     return sum(seq) 

但是,如果你想要的是什麼字典的所有序列的總和,你可以使用,而不是做多態的功能在Python的唯一途徑以下,

def collatz_seq_sum(seq): 
    """returns the sum of all elements to a given Collatz sequence""" 
    if isinstance(seq, dict): 
     return sum([sum(seqi) for i, seqi in seq.items()]) 
    else: 
     return sum(seq) 
+0

感謝您的意見。那麼,不完全是。我不希望'collat​​z_seq_sum'根本不打算使用'seq'的數據類型,因爲我不認爲'collat​​z_seq_sum'的作用是檢查數據類型。計算金額是它的工作;沒有其他的。 – 6q9nqBjo

+0

你的意思是說你想讓collat​​z_seq_sum在任何數據類型上工作,而不檢查數據類型嗎? –

+0

是的,這是基本的想法,因爲我不想在處理數百個函數時做幾乎相同的檢查。 – 6q9nqBjo

0

Python 3.4+ - functools.singledispatch讓你過載基於參數類型的函數定義。

from functools import singledispatch 

@singledispatch 
def collatz_seq_sum(seq): 
    '''returns the sum of all elements to a given Collatz sequence''' 
    raise NotImplementedError("I can't handle that data type") 

@collatz_seq_sum.register(list) 
def _(seq): 
    return sum(seq) 

@collatz_seq_sum.register(dict) 
def _(seq): 
    return {key: sum(values) for key, values in seq.items()} 

>>> collatz_seq_sum([1,2,3,4,5]) 
15 
>>> collatz_seq_sum({'a': [1,1,1,1], 'b': [2,2,2,2]}) 
{'a': 4, 'b': 8} 

調用collatz_seq_sum比列表或字典其他東西將引發NotImplementedError

+0

感謝您的輸入。這也是一個非常有趣的方法。你使用了「超載」這個詞。你的代碼是Python的裝飾器功能的應用程序嗎? @標誌讓我想起了它。 – 6q9nqBjo

+0

@ 6q9nqBjo,我從它的文檔中取出了超載這個詞。這是一個裝飾者 - 我沒有花時間去看看它是如何實現的。在我的答案中有一個鏈接到文檔。 – wwii

相關問題