python中if elif语句优化_关于python:当else被做得最多时,最有效的if-elif-elif-else语句的方法是什么?...

我有一个in-if-elif-elif-else语句,其中99%的时间执行else语句:

if something == 'this':

doThis()

elif something == 'that':

doThat()

elif something == 'there':

doThere()

else:

doThisMostOfTheTime()

这个构造做了很多,但是因为它在碰到其他东西之前就已经克服了所有的条件,所以我觉得这不是很有效,更不用说Python了。另一方面,它需要知道是否满足这些条件中的任何一个,因此它无论如何都应该测试它。

有人知道这是否以及如何能更有效地做到,或者这仅仅是最好的方法吗?

你能不能把你正在运行的东西……链上,这样一个条件将匹配的所有元素都在一端,其余的都在另一端?如果是这样的话,你可以看看这是否更快/更优雅。但是请记住,如果没有性能问题,那么现在担心优化还为时过早。

rel stackoverflow.com/questions/374239/…

@帕塔苏-不幸的是,我确实有一个巨大的性能问题。这个程序日夜运行,分析大量数据。只是我的C++技能没有达到标准(我喜欢Python),我没有重写它。

这三个特例有什么共同点吗?例如,您可以在if not something.startswith("th"): doThisMostOfTheTime()子句中进行if not something.startswith("th"): doThisMostOfTheTime()和其他比较。

@Timpietzcker——不幸的是,他们没有什么共同点。它们可以是3个特定的数字或一个特定的字符串,如果它是任何其他数字或字符串(在2000+选项中),则必须执行else操作。

@Kramer65如果是这么长的if/elif链…它可能会很慢,但要确保实际分析代码,并从优化最耗时的部分开始。

这些比较是每个something值只进行一次,还是对同一个值多次进行类似比较?

代码…

options.get(something, doThisMostOfTheTime)()

…看起来应该更快,但实际上比if慢……elif…else构造,因为它必须调用一个函数,这在一个紧凑的循环中可能是一个很大的性能开销。

考虑这些例子…

1.Py

something = 'something'

for i in xrange(1000000):

if something == 'this':

the_thing = 1

elif something == 'that':

the_thing = 2

elif something == 'there':

the_thing = 3

else:

the_thing = 4

2.Py

something = 'something'

options = {'this': 1, 'that': 2, 'there': 3}

for i in xrange(1000000):

the_thing = options.get(something, 4)

3.Py

something = 'something'

options = {'this': 1, 'that': 2, 'there': 3}

for i in xrange(1000000):

if something in options:

the_thing = options[something]

else:

the_thing = 4

4.Py

from collections import defaultdict

something = 'something'

options = defaultdict(lambda: 4, {'this': 1, 'that': 2, 'there': 3})

for i in xrange(1000000):

the_thing = options[something]

…并注意它们使用的CPU时间量…

1.py: 160ms

2.py: 170ms

3.py: 110ms

4.py: 100ms

…使用time(1)的用户时间。

选项4确实有额外的内存开销,可以为每个不同的键未命中添加一个新项,因此,如果您希望有无限数量的不同键未命中,我将使用选项3,这仍然是对原始构造的一个显著改进。

python有switch语句吗?

@内森海菲尔德号

呃……到目前为止,这是我听到的关于Python的唯一我不关心的事情……我想肯定会有什么事发生。

-1你说使用dict比较慢,但是你的计时实际上表明它是第二快的选择。

@马金,我是说,江户十一〔七〕是慢的,那就是江户十一〔八〕是他们中最慢的。

根据记录,三个和四个也比在try/except结构中捕获关键错误快得多。

我会创建一本字典:

options = {'this': doThis,'that' :doThat, 'there':doThere}

现在只使用:

options.get(something, doThisMostOfTheTime)()

如果optionsdict中没有找到something,那么dict.get将返回默认值doThisMostOfTheTime。

一些时间比较:

脚本:

from random import shuffle

def doThis():pass

def doThat():pass

def doThere():pass

def doSomethingElse():pass

options = {'this':doThis, 'that':doThat, 'there':doThere}

lis = range(10**4) + options.keys()*100

shuffle(lis)

def get():

for x in lis:

options.get(x, doSomethingElse)()

def key_in_dic():

for x in lis:

if x in options:

options[x]()

else:

doSomethingElse()

def if_else():

for x in lis:

if x == 'this':

doThis()

elif x == 'that':

doThat()

elif x == 'there':

doThere()

else:

doSomethingElse()

结果:

>>> from so import *

>>> %timeit get()

100 loops, best of 3: 5.06 ms per loop

>>> %timeit key_in_dic()

100 loops, best of 3: 3.55 ms per loop

>>> %timeit if_else()

100 loops, best of 3: 6.42 ms per loop

对于10**5不存在的密钥和100个有效密钥:

>>> %timeit get()

10 loops, best of 3: 84.4 ms per loop

>>> %timeit key_in_dic()

10 loops, best of 3: 50.4 ms per loop

>>> %timeit if_else()

10 loops, best of 3: 104 ms per loop

因此,对于普通字典来说,使用key in options检查密钥是最有效的方法:

if key in options:

options[key]()

else:

doSomethingElse()

我现在才知道字典的威力……:)

options = collections.defaultdict(lambda: doThisMostOfTheTime, {'this': doThis,'that' :doThat, 'there':doThere}); options[something]()的效率略高。

想法很酷,但没那么可读。另外,您可能希望分离optionsdict以避免重建它,从而将逻辑的一部分(但不是全部)远离使用点。不过,好把戏!

你知道这是否更有效吗?我猜是因为它执行的是哈希查找,而不是简单的条件检查或三次检查,所以速度较慢。问题在于代码的效率而不是紧凑性。

@布莱恩奥克利,我增加了一些时间比较。

最后是我的第一枚Populist徽章。

实际上,做try: options[key]() except KeyError: doSomeThingElse()应该更有效(因为在if key in options: options[key]()中,你在字典中搜索两次key。

你能用派比吗?

保留您的原始代码,但在pypy上运行它会使我的速度提高50倍。

CPython:

matt$ python

Python 2.6.8 (unknown, Nov 26 2012, 10:25:03)

[GCC 4.2.1 Compatible Apple Clang 3.0 (tags/Apple/clang-211.12)] on darwin

Type"help","copyright","credits" or"license" for more information.

>>>

>>> from timeit import timeit

>>> timeit("""

... if something == 'this': pass

... elif something == 'that': pass

... elif something == 'there': pass

... else: pass

...""","something='foo'", number=10000000)

1.728302001953125

Pypy:

matt$ pypy

Python 2.7.3 (daf4a1b651e0, Dec 07 2012, 23:00:16)

[PyPy 2.0.0-beta1 with GCC 4.2.1] on darwin

Type"help","copyright","credits" or"license" for more information.

And now for something completely different: ``a 10th of forever is 1h45''

>>>>

>>>> from timeit import timeit

>>>> timeit("""

.... if something == 'this': pass

.... elif something == 'that': pass

.... elif something == 'there': pass

.... else: pass

....""","something='foo'", number=10000000)

0.03306388854980469

你好,Foz。谢谢你的小费。事实上,我已经在使用pypy(喜欢它),但我仍然需要提高速度。:)

哦,好吧!在此之前,我尝试预先计算"this"、"that"和"there"的哈希值,然后比较哈希代码而不是字符串。结果发现这比原来慢了两倍,所以看起来字符串比较在内部已经得到了很好的优化。

这是一个将动态条件转换为字典的if示例。

selector = {lambda d: datetime(2014, 12, 31) >= d : 'before2015',

lambda d: datetime(2015, 1, 1) <= d < datetime(2016, 1, 1): 'year2015',

lambda d: datetime(2016, 1, 1) <= d < datetime(2016, 12, 31): 'year2016'}

def select_by_date(date, selector=selector):

selected = [selector[x] for x in selector if x(date)] or ['after2016']

return selected[0]

这是一种方法,但可能不是最适合用Python的方法,因为对于不精通Python的人来说,它的可读性较低。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值