避免使用type()比较,其中多态不起作用

时间:2011-04-29 18:56:31

标签: python types

我在How to Think Like a Computer Scientisthere)中遇到了以下内容:

def recursive_sum(nested_num_list):
    sum = 0
    for element in nested_num_list:
        if type(element) == type([]):
            sum = sum + recursive_sum(element)
        else:
            sum = sum + element
    return sum

我对使用type(element)== type([])感到震惊。这不仅是不好的做法,而且这个功能不适用于任何其他序列类型。多态性是避免类型比较的典型方法,但不能在此处使用。在这种情况下如何避免类型比较?我考虑过:

def recursive_sum(nested_sum_list):
    sum = 0
    for element in nested_num_list:
        try:
            sum += element
        except TypeError:
            sum += recursive_sum(element)
    return sum

这使得该功能适用​​于其他序列,但仍然有点粗略。谢谢!

7 个答案:

答案 0 :(得分:3)

您可以使用isinstance(element, collections.Sequence)检查元素是否为序列。

答案 1 :(得分:2)

“sum”函数采用迭代,所以我会检查元素是否实现了__iter__方法,使用“hasattr”内置函数。

像这样:

def recursive_sum(nested_num_list):
    sum = 0
    for element in nested_num_list:
        if hasattr(element, '__iter__'):
            sum = sum + recursive_sum(element)
        else:
            sum = sum + element
    return sum

答案 2 :(得分:1)

对于aribtrarily嵌套列表的展平,您将始终需要某种检查来测试元素本身是可迭代还是叶节点。我不会将flattening与在一个函数中计算总和相结合,而是定义一个只进行展平的生成器函数:

def flatten(x):
    try:
        it = iter(x)
    except TypeError:
        yield x
    else:
        for i in it:
            for j in flatten(i):
                yield j

这样,您将在单个函数中包含所有丑陋的位。对于嵌套序列x,您现在可以执行

sum(flatten(x))

获得递归总和。

答案 3 :(得分:1)

列表中的事情:

>>> import collections
>>> hasattr(element, '__getitem__')
True
>>> not hasattr(element, 'keys')
True
>>> isinstance(element, collections.Sequence)
True
>>> hasattr(element, '__iter__')
True

字符串的真实情况:

>>> string = '1234'
>>> hasattr(string, '__getitem__')
True
>>> not hasattr(string, 'keys')
True
>>> isinstance(string, collections.Sequence)
True
>>> hasattr(string, '__iter__')
False

答案 4 :(得分:0)

你在这里看到的不是我所知道的任何语言的多态性。 +=列表意味着一件事,对于数字而言另一件事。你希望+=列表表示不寻常的东西(总结所有元素并返回总和) - 但这只对你的具体例子有意义。对于其他(大多数,我会说)列表的使用,+=的原始含义更方便。

为了使这种行为真正具有多态性,您可以从list派生并使+=表示您想要的 - 然后您就不需要这些黑客了。

顺便说一句:

if type(element) == type([]):

应改写为:

if isinstance(element, list):

答案 5 :(得分:0)

您正在检查是否可以将元素添加到int中,这不是您想要的。

虽然try并不坏:尝试将其用作可迭代的 - 如果它有效,则它是可迭代的:

def recursive_sum(nested_sum_list):
    sum = 0
    # this raises TypeError if element is not a sequence
    for element in nested_num_list: 
        try:
            sum += recursive_sum(element)
        except TypeError:
            sum += element
    return sum

迭代物也有typeclass

import collections
print isinstance(element, collections.Iterable)

基本上只搜索__iter__方法。

答案 6 :(得分:0)

此函数的目的不是普遍适用于添加嵌套结构,它只是为了说明递归而创建的。

添加更复杂的序列类型检查,尝试和除外,或者添加除数字之外的其他东西的能力会使函数 less 作为递归的学习工具。

话虽如此,isinstance(element, (list, tuple))在这里可能更合适,并且不会增加任何复杂性。