Python如何优雅地处理不同数据结构的使用?

时间:2017-01-02 15:18:09

标签: python data-structures

我使用的是Python 3.5,这是我目前正在处理的代码:

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

你对此有什么解决方案吗?非常感谢你提前。

3 个答案:

答案 0 :(得分:0)

如果我理解正确,你希望collatz_seq_sum能够同时处理一个关于折叠序列的字典或一个单独的折叠序列。对于字典,您希望函数返回单个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)

但是,如果你想要的是dict的所有序列的总和,你可以使用以下代码,

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)

答案 1 :(得分:0)

在python中为函数执行多态的唯一方法是检查给定参数的类型:

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

如果你想让一个函数的行为不同,这取决于输入的类型,这是可行的方法。

答案 2 :(得分: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}

使用list或dict以外的内容调用collatz_seq_sum会引发NotImplementedError