1

我有这段代码检查条件:

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 循环,它会消耗更多时间吗?

4

3 回答 3

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_WORDSand POSITIVE_WORDS,则最后两个ifs 的顺序会影响结果。这不是好的做法。
于 2017-08-30T09:20:21.927 回答
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-loop 并且更短 - 但是根据我和 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

您甚至可以使用andfor减少行数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))

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

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 答案中的正则表达式建议。但是,设置方法仅表示“小建议”-我怀疑它是否可以应用于您的情况。但是你需要判断。

于 2017-08-30T09:21:46.280 回答
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此外,您可能可以通过首先转换为 a of(小写)单词来加快检查速度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(),使用 egre.findall(r"\w+")来查找没有标点符号的单词。

根据肯定列表和否定列表的大小,可能还可以反转检查,例如any(word in POSITIVE_WORDS for word in add_data.split()),特别是如果那些已经是set快速查找的结构。

于 2017-08-30T09:31:33.247 回答