Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有没有更好的方法来写“连续”呢;或;Python中的语句?_Python_Conditional - Fatal编程技术网

有没有更好的方法来写“连续”呢;或;Python中的语句?

有没有更好的方法来写“连续”呢;或;Python中的语句?,python,conditional,Python,Conditional,我自己找不到任何“好”答案的简单问题: 假设我有以下条件: if 'foo' in mystring or 'bar' in mystring or 'hello' in mystring: # Do something pass 根据情况,或语句的数量可能会更长 在不牺牲性能的情况下,有没有一种“更好的”(更像蟒蛇)的写作方式 如果考虑使用any(),但它需要一个类似布尔元素的列表,因此我必须首先构建该列表(在这个过程中放弃短路计算),因此我认为它效率较低 非常感谢。一种方法

我自己找不到任何“好”答案的简单问题:

假设我有以下条件:

if 'foo' in mystring or 'bar' in mystring or 'hello' in mystring:
    # Do something
    pass
根据情况,
语句的数量可能会更长

在不牺牲性能的情况下,有没有一种“更好的”(更像蟒蛇)的写作方式

如果考虑使用
any()
,但它需要一个类似布尔元素的列表,因此我必须首先构建该列表(在这个过程中放弃短路计算),因此我认为它效率较低

非常感谢。

一种方法是

if any(s in mystring for s in ('foo', 'bar', 'hello')):
    pass
您迭代的是一个元组,它是建立在函数编译的基础上的,因此它不应该低于您的原始版本

如果您担心元组会变得太长,您可以这样做

def mystringlist():
    yield 'foo'
    yield 'bar'
    yield 'hello'
if any(s in mystring for s in mystringlist()):
    pass

这听起来像是正则表达式的工作

import re

if re.search("(foo|bar|hello)", mystring):
    # Do something
    pass
它也应该更快。特别是如果您提前编译正则表达式

如果自动生成正则表达式,可以使用
re.escape()
确保没有特殊字符破坏正则表达式。例如,如果
words
是要搜索的字符串列表,则可以生成如下模式:

pattern = "(%s)" % ("|".join(re.escape(word) for word in words), )

您还应该注意,如果您有
m
单词,并且您的字符串有
n
个字符,那么您的原始代码具有
O(n*m)
复杂性,而正则表达式具有
O(n)
复杂性。尽管Python正则表达式并不是真正的理论上的comp-sci正则表达式,也不总是复杂的,但在这个简单的例子中,它们是复杂的。

因为您是针对
mystring
逐字处理的,所以mystring肯定可以作为一个集合使用。然后只取包含
mystring
中单词的集合与目标单词组之间的交点:

In [370]: mystring=set(['foobar','barfoo','foo'])

In [371]: mystring.intersection(set(['foo', 'bar', 'hello']))
Out[371]: set(['foo'])
逻辑“或”是两个集合的交集的成员

使用集合也更快。以下是相对于生成器和正则表达式的相对计时:

f1:  generator to test against large string 
f2:  re to test against large string 
f3:  set intersection of two sets of words 

    rate/sec      f2     f1     f3
f2   101,333      -- -95.0% -95.5%
f1 2,026,329 1899.7%     -- -10.1%
f3 2,253,539 2123.9%  11.2%     --
因此,生成器和操作中的
比正则表达式快19倍,集合交集比正则表达式快21倍,比生成器快11%

以下是生成计时的代码:

import re

with open('/usr/share/dict/words','r') as fin:
     set_words={word.strip() for word in fin}

s_words=' '.join(set_words)
target=set(['bar','foo','hello'])
target_re = re.compile("(%s)" % ("|".join(re.escape(word) for word in target), ))

gen_target=(word for word in ('bar','foo','hello'))

def f1():
    """ generator to test against large string """        
    if any(s in s_words for s in gen_target):
        return True

def f2():
    """ re to test against large string """
    if re.search(target_re, s_words):
        return True

def f3():
    """ set intersection of two sets of words """
    if target.intersection(set_words):
        return True

funcs=[f1,f2,f3]
legend(funcs)
cmpthese(funcs)        

如果您有一个已知的要检查的项目列表,您也可以将其写为

if mystring in ['foo', 'bar', 'hello']:

您可能无法获得确保比较顺序的好处(我认为Python不需要从左到右检查列表元素),但如果您知道“foo”比“bar”更可能出现,那么这只是一个问题。

谢谢。但这项技术不是阻止了短路优化吗?它是一个生成器,而不是列表。不是
(mystring中的s表示“foo”、“bar”、“hello”中的s)
是一个生成器表达式,这意味着它不是作为一个整体立即计算的,而是按需计算的
any()
在看到第一个真值时停止迭代,因此不会检查其余值。仔细阅读生成器表达式。@gnibbler:我没有说过
任何
都不会短路。我担心名单的结构不会。但是因为它实际上是一个发电机,它改变了一切。哦,如果你做了
any([s in mystring for s in…])
,你就不会短路。
[]
列表理解总是创建一个完整的列表
any()
不会对其进行迭代,但在调用
any
之前仍会对其进行计算。但是,如果要查找的任何“单词”包含特殊的正则表达式,则必须小心characters@gnibbler:是的。相反,通过使用模式匹配,您可能可以编写更少的代码。如果您正在执行自动生成正则表达式之类的操作,则可以使用
re.escape()
。确实可以,您应该将其添加到回答中谢谢您的建议。我的真实案例场景与这种技术不太兼容(但你显然猜不到)。投票赞成公平,因为答案是正确的,可以帮助别人。确实更快!可能是因为正则表达式只需要遍历字符串一次。这与公认的答案有何不同?唯一的区别是您使用的是
集合
而不是
元组
,否则就完全一样了。@cha0site:公认的答案还提出了一个用于大列表的函数。我认为一套是更好的方式,使相同的。这也提出了两套——不使用
any
这不是一回事。当
mystring='helloworld'
时,问题中的条件也会成立。这一个不会。很好的一点,谢谢-正如你所说,不完全一样的事情,也许不适合具体的问题。