【问题标题】:Test if tuple contains only None values with Python使用 Python 测试元组是否仅包含 None 值
【发布时间】:2014-02-13 04:29:21
【问题描述】:

我需要查找我的元组是否只包含 None 值。

我使用此代码,但我不确定这是不是好习惯:

# coding=utf8

def isOnlyNoneValuesTuple(t):
    """
    test if tuple contains only None values
    """
    if not len(tuple(itertools.ifilter(None, t))):
        return True
    else:
        return False

print isOnlyNoneValuesTuple((None,None,None,None,None,None,None,None,None,None,None,None,))
print isOnlyNoneValuesTuple((None,None,None,"val",None,None,None,None,))

你知道其他好的测试方法吗?

感谢您的意见

【问题讨论】:

    标签: python python-2.7 tuples nonetype


    【解决方案1】:
    return all(item is None for item in t)
    

    【讨论】:

    • 完美!谢谢。 all是我的朋友^^
    • @GeoStoneMarten: All? No, All!.
    【解决方案2】:
    return set(t) == {None}
    

    虽然我想我会在实践中使用 all()。

    【讨论】:

    • 同意——除了很好的代码高尔夫之外,对于那些比 genexprs 的工作原理更清楚集合意味着什么的人来说,它可能有助于理解……但事实上它不会短路, 为具有许多不同值的输入浪费内存,并且如果任何元素不可散列则失败,这意味着我可能也不会在实践中使用它。
    • 最重要的是,它可能应该为空元组返回 True 而这不会。但是展示一个替代方案不会有什么坏处:-)
    • 啊,没想到这个问题。
    • 它可以工作,但all 更好,不是吗?我正在解析带有光标的表并忽略只有 None、0 或空字符串的行。
    • 是的,一切都变得更好了。如果你只是想检查元组中是否有任何东西被评估为 True(None、0 和 "" 都是 Falsy),那么它就像if any(t) 一样简单
    【解决方案3】:
    return t.count(None) == len(t)
    

    而且比使用all更快:

    >>> setup = 't = [None, None]*100; t[1] = 1'
    >>> timeit.timeit('all(item is None for item in t)', setup=setup)
    0.8577961921691895
    >>> timeit.timeit('t.count(None) == len(t)', setup=setup)
    0.6855478286743164
    

    并且all 的速度根据非None 元素的索引而降低:

    >>> setup = 't = [None, None]*100; t[100] = 1'
    >>> timeit.timeit('all(item is None for item in t)', setup=setup)
    8.18800687789917
    >>> timeit.timeit('t.count(None) == len(t)', setup=setup)
    0.698199987411499
    

    但是大列表更快:

    >>> setup = 't = [None, None]*10000; t[100] = 1'
    >>> timeit.timeit('t.count(None) == len(t)', setup=setup)
    47.24849891662598
    >>> timeit.timeit('all(item is None for item in t)', setup=setup)
    8.114514112472534
    

    并非总是如此:

    >>> setup = 't = [None, None]*10000; t[1000]=1'
    >>> timeit.timeit('t.count(None) == len(t)', setup=setup)
    47.475088119506836
    >>> timeit.timeit('all(item is None for item in t)', setup=setup)
    72.77452898025513
    

    我为自己做出的关于所有速度或计数的结论 - 很大程度上取决于数据。如果您在非常大的列表中拥有所有 None 的可能性 - 不要使用所有,在这种情况下它非常慢。

    【讨论】:

    • 除了如果有任何非None 值会慢得多,因为它不会短路。
    • 我使用包含 10,000 到 300 万行的 insertcursor 将表移动到表。并且没有很多空行。我认为它在 10 到 2000 行之间(感谢 MS Excel ...)
    • 尝试使用 N=10000 或 N=3000000 而不是 N=100,看看哪个更快。使用 10000 时,all 获得 549ns/loop,count 获得 69.4us/loop(慢 100 倍)。
    • @abarnert on N=1000 count 仍然比all 快 2 倍,在 t[100]=1 时比 all 慢近 6 倍......这很奇怪
    • @ndpu:对于 N=1000,第一个非None 为 100,我得到 5.01us 与 6.89us,后者更慢,而不是快 2 倍。但是,当 OP 告诉我们他的域介于 10000 和 3000000 之间时,谁在乎交叉点是 1000 还是 2000?
    【解决方案4】:

    我赞同 BrenBarn 的回答,它非常 Pythonic。但既然你也问了关于测试代码的问题,我会加两分钱。

    您可以利用 Python 允许您将包含单个元素的列表乘以因子 n 来获得包含相同元素 n 次的列表来创建适当的数据结构:

    print(isOnlyNoneValuesTuple(tuple(10 * [None])))
    print(isOnlyNoneValuesTuple(tuple(3 * [None] + ["val"] + 4 * [None])))
    

    【讨论】:

    • 你也可以将元组相乘,tuple(10 * [None])10 * (None,) 一样(但要注意最后一个逗号)
    • 谢谢,但这不是我的问题。元组是行游标的结果。
    • @RemcoGerlich 感谢您提及!不过,我不会将其添加到我的答案中,因为我认为在这里提到两个版本都很好:)
    • @GeoStoneMarten 那么“你知道测试它的其他良好做法”是什么意思?在任何情况下,测试你的代码总是一个好主意;)使用虚拟值这样做很常见......
    • @ndpu 解释了几个良好实践的案例。他明白我的意思。谢谢
    猜你喜欢
    • 2015-10-16
    • 2013-08-26
    • 1970-01-01
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-13
    相关资源
    最近更新 更多