一种更有效的使用 if 条件的 pythonic 方式
A more efficient pythonic way to use if condition
我有这段检查条件的代码:
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 循环,它会消耗更多时间吗?
由于 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
有几件事:
- 为什么搜索
NEGATIVE_WORDS
而不是 POSITIVE_WORDS
时调用 .lower()
?
- 如果
add_data
同时包含NEGATIVE_WORDS
和POSITIVE_WORDS
,最后两个if
的顺序将影响结果。这不是好的做法。
This is quite hard to follow (in my opinion), so I was wondering if anyone can suggest something more pythonic with shorter lines?
通常 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
Could I for example merge the two for loops?
不是真的。因为 NEGATIVE_WORDS
循环应该优先于 POSITIVE_WORDS
循环(至少在您的代码中)。除了你的意思是把它分解成一个函数。那就先看看吧
If I merge two for loops, would it consumes more time?
我不确定你所说的 "merging" 循环是什么意思,但如果你想要它更短,你可以在上面的方法中使用 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
您甚至可以通过对 return
使用 and
来减少行数。我不会推荐它,因为这样的结构不会提高可读性,但这是你的决定,这是 "shorten" 代码的一种方式:
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
s 来加快速度。这将要求您只查找整个单词匹配(而不是部分匹配,而不是多词匹配):
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 答案中的正则表达式建议。但是 set 方法仅表示 "small suggestion" - 我怀疑它是否适用于您的情况。但是你需要判断。
除了使用 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 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 循环,它会消耗更多时间吗?
由于 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
有几件事:
- 为什么搜索
NEGATIVE_WORDS
而不是POSITIVE_WORDS
时调用.lower()
? - 如果
add_data
同时包含NEGATIVE_WORDS
和POSITIVE_WORDS
,最后两个if
的顺序将影响结果。这不是好的做法。
This is quite hard to follow (in my opinion), so I was wondering if anyone can suggest something more pythonic with shorter lines?
通常 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
Could I for example merge the two for loops?
不是真的。因为 NEGATIVE_WORDS
循环应该优先于 POSITIVE_WORDS
循环(至少在您的代码中)。除了你的意思是把它分解成一个函数。那就先看看吧
If I merge two for loops, would it consumes more time?
我不确定你所说的 "merging" 循环是什么意思,但如果你想要它更短,你可以在上面的方法中使用 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
您甚至可以通过对 return
使用 and
来减少行数。我不会推荐它,因为这样的结构不会提高可读性,但这是你的决定,这是 "shorten" 代码的一种方式:
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
s 来加快速度。这将要求您只查找整个单词匹配(而不是部分匹配,而不是多词匹配):
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 答案中的正则表达式建议。但是 set 方法仅表示 "small suggestion" - 我怀疑它是否适用于您的情况。但是你需要判断。
除了使用 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
具有快速查找的结构。