在Python中将字符串与多个项目进行比较

29

我正在尝试将一个名为facility的字符串与多个可能的字符串进行比较,以测试它是否有效。有效的字符串包括:

auth, authpriv, daemon, cron, ftp, lpr, kern, mail, news, syslog, user, uucp, local0, ... , local7

除了以下方法,还有更高效的方式吗?

if facility == "auth" or facility == "authpriv" ...

寻找子字符串,可以尝试访问 https://dev59.com/a3A75IYBdhLWcg3wRWsU - tripleee
许多新手被这个事实绊倒了:if facility == "auth" or "authpriv"并不是他们想要的(它检查facility == "auth"是否为真,或者"authpriv"不是一个空字符串)。 - tripleee
1
对于查找重复问题的人来说,如果你发现有人在进行 if variable == literal or literal or literal: 这样的测试,那么 为什么 "a == x or y or z" 总是评估为 True? 是一个更好的重复目标。 - ShadowRanger
3个回答

62

如果你的字符串列表非常长,可以考虑使用 set:

accepted_strings = {'auth', 'authpriv', 'daemon'}

if facility in accepted_strings:
    do_stuff()

在集合中测试元素是否存在平均时间复杂度为O(1)。


是的,那将是正确的方法。http://wiki.python.org/moin/PythonSpeed 对于任何对Python效率有一般概述感兴趣的人来说都是非常好的阅读材料。不过你不会知道set()的平均时间吧? - waffle paradox
这种方法的一个潜在缺点是它们的迭代顺序变得不可预测,但只有在您将它们用于其他用途(例如打印帮助消息中接受的字符串列表)时才会出现问题。 - Ben
6
在Python2.7 / 3中,您可以编写accepted_strings = {'auth','authpriv','daemon'},以便在构建集之前不创建任何列表。 - Michał Bentkowski
2
在更现代的Python中,通过将测试内联到if facility in {'auth','authpriv','daemon'}:(只要所有选项都是像这种情况下的常量文字),您将受益一些; 当执行此操作的函数被编译并存储在函数的常量中时,它将被转换为frozenset,其中每次到达accepted_strings = {'auth','authpriv','daemon'}行时都会重建该set - ShadowRanger

11

除非你的字符串列表变得异常长,否则像这样做可能是最好的:

accepted_strings = ['auth', 'authpriv', 'daemon'] # etc etc 

if facility in accepted_strings:
    do_stuff()

哦,太棒了,谢谢。如果我的列表实际上变得非常长会发生什么? - user623990
那只是一个小玩笑,因为你不想手动输入一万个字符串列表。 - waffle paradox
这是我最初使用的选项,但由于我的应用程序可能会增长,我将接受@pillmucher的答案。谢谢+1 - user623990
没问题。他的方法可能更安全,但需要注意的是,在集合和列表包含方面,你现在必须拥有比目前大几个数量级的列表才能真正开始注意到它们之间的差异。只要记住,过早优化是万恶之源。 ;) - waffle paradox

3

要高效地检查一个字符串是否与多个字符串中的一个匹配,请使用以下方法:

allowed = set(('a', 'b', 'c'))
if foo in allowed:
    bar()

set()是散列的、无序的集合,用于优化判断给定项是否在其中。


如果你担心速度问题,使用元组来迭代创建集合比使用列表略快。 - agf
我不知道为什么。我的专长是CPython字节码操作。 - Colin Valliant
4
在Python 2.7和3中,你可以使用集合字面值语法:{'a', 'b', 'c'}。 - caleb531

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接