如果条件,使用更有效的pythonic方式

时间:2017-08-30 09:04:19

标签: python if-statement search coding-efficiency

我有这段代码检查条件:

def is_important(data_row):
    if data_row.get('important', None):
        return True
    add_data = get_additional_data(data_row)
    for word in NEGATIVE_WORDS:
        if word in add_data.lower():
            return False
    for word in POSITIVE_WORDS:
        if word in add_data.lower():
            return True
    return False

这很难遵循(在我看来),所以我想知道是否有人可以用更短的线条建议更多的pythonic?我可以将两个for循环合并吗?如果我合并两个for循环,它会消耗更多时间吗?

3 个答案:

答案 0 :(得分:2)

由于any很像你的显式循环,它更紧凑,短路

def is_important(data_row):
    if data_row.get('important', None):
        return True
    add_data = get_additional_data(data_row)
    if any(word in add_data.lower() for word in NEGATIVE_WORDS):  # negative check takes precedence.
        return False
    if any(word in add_data.lower() for word in POSITIVE_WORDS):
        return True
    return False

关于这一点的几件事:

  • 为什么在搜索.lower()而不是NEGATIVE_WORDS时拨打POSITIVE_WORDS
  • 如果add_data同时包含NEGATIVE_WORDSPOSITIVE_WORDS,则最后两个if的顺序将影响结果。这不是一个好习惯。

答案 1 :(得分:2)

  

这很难遵循(在我看来),所以我想知道是否有人可以用更短的线条建议更多的pythonic?

通常pythonic并不意味着更短的线条。 Pythonic代码应该易于阅读和遵循(至少有一点背景)。因此,如果您发现难以阅读,您可以将其纳入不同的功能:

# I'm not sure if the function name is a good fit, it's just a suggestion.
def contains_at_least_one(data, words):  
    for word in words:
        if word in data:
            return True
    return False

def is_important(data_row):
    if data_row.get('important', None):
        return True
    add_data = get_additional_data(data_row).lower()
    if contains_at_least_one(add_data, NEGATIVE_WORDS):
        return False
    if contains_at_least_one(add_data, POSITIVE_WORDS):
        return True
    return False
  

我可以将两个for循环合并吗?

不是真的。因为NEGATIVE_WORDS循环应优先于POSITIVE_WORDS循环(至少在您的代码中)。除非你的意思是将其分解为函数。然后先看看。

  

如果我合并两个for循环,它会消耗更多时间吗?

我不确定你的意思是什么"合并"循环,但如果你想缩短它,你可以在上面的方法中使用any。它相当于for - 循环和更短 - 但是,根据我和StefanPochmans的基准测试,速度较慢:

def contains_at_least_one(data, words):
    return any(word in data for word in words)

def is_important(data_row):
    if data_row.get('important', None):
        return True
    add_data = get_additional_data(data_row).lower()
    if contains_at_least_one(add_data, NEGATIVE_WORDS):
        return False
    if contains_at_least_one(add_data, POSITIVE_WORDS):
        return True
    return False

您甚至可以使用and return来减少行数。我不推荐它,因为这样的结构不会提高可读性,但这是你的决定,它是缩短"的一种方式。代码:

def is_important(data_row):
    if data_row.get('important', None):
        return True
    add_data = get_additional_data(data_row).lower()
    return (not contains_at_least_one(add_data, NEGATIVE_WORDS) and
            contains_at_least_one(add_data, POSITIVE_WORDS))

有点牵强,但也许你甚至可以用set来加快速度。这将要求您只查找整个单词匹配(不是部分匹配,而不是多字匹配):

def contains_at_least_one(data, words):
    return data.intersection(words)

def is_important(data_row):
    if data_row.get('important', None):
        return True
    add_data = set(get_additional_data(data_row).lower().split())  # set and split!
    return not contains_at_least_one(add_data, NEGATIVE_WORDS) and contains_at_least_one(add_data, POSITIVE_WORDS)

如果您不想要标点符号来破坏匹配,请参阅tobias_k答案中的正则表达式建议。然而,设定的方法仅仅意味着"小建议" - 我怀疑它可以适用于你的情况。但是你需要判断它。

答案 2 :(得分:1)

除了使用any之外,你还可以将不同的条件组合成一个return语句,不过这是否更明确可能是一个意见问题。

def is_important(data_row):
    add_data = get_additional_data(data_row)
    return (data_row.get('important', None)
        or (not any(word in add_data.lower() for word in NEGATIVE_WORDS)
            and any(word in add_data         for word in POSITIVE_WORDS)))

虽然如果get_additional_data费用昂贵,您可以先将if分开。

此外,您可以先将add_data转换为set个(小写)字词来加快检查速度,但这会略微改变逻辑,因为不匹配单词片段。

def is_important(data_row):
    add_data = set((word.lower() for word in get_additional_data(data_row).split()))
    return (data_row.get('important', None)
        or (not any(word in add_data for word in NEGATIVE_WORDS)
            and any(word in add_data for word in POSITIVE_WORDS)))

或者,使用例如.split()而不是re.findall(r"\w+")any(word in POSITIVE_WORDS for word in add_data.split())找到没有标点符号的单词。

根据正面和负面列表的大小,也可能需要付清以反转支票,例如set,特别是如果这些已经def validate_number(s): try: return float(s) except (ValueError, TypeError): return s data = [validate_number(s) for s in data] 具有快速查找的结构。