当 else 操作最多时,编写 if-elif-elif-else 语句的最有效方法是什么?

2025-02-24 09:30:00
admin
原创
68
摘要:问题描述:我有一个 if-elif-elif-else 语句,其中 99% 的时间都会执行 else 语句:if something == 'this': doThis() elif something == 'that': doThat() elif something == 'there'...

问题描述:

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

if something == 'this':
    doThis()
elif something == 'that':
    doThat()
elif something == 'there':
    doThere()
else:
    doThisMostOfTheTime()

这种结构已经实现了很多次,但由于它在遇到 else 之前会先检查所有条件,所以我感觉这不是很高效,更不用说 Pythonic 了。另一方面,它确实需要知道这些条件是否得到满足,所以无论如何都应该测试它。

是否有人知道是否可以以及如何更有效地完成此操作,或者这是否只是最好的方法?


解决方案 1:

代码...

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,这仍然是对原始构造的显着改进。

解决方案 2:

我会创建一本字典:

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

现在只需使用:

options.get(something, doThisMostOfTheTime)()

如果在字典something中找不到,optionsdict.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()

解决方案 3:

你会使用 pypy 吗?

保留原始代码但在 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

皮皮:

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

解决方案 4:

下面是一个将具有动态条件的 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 的人来说,它的可读性较差。

解决方案 5:

我尝试使用 Python 3.10 中引入的 match 语句:

5.py

something = 'something'
for i in range(10000000):
    match something:
        case "this":
            the_thing = 1
        case "that":
            the_thing = 2
        case "there":
            the_thing = 3
        case _:
            the_thing = 4

以下是我使用 3.10.0 获得的结果:

1.py:1.4s 2.py:0.9s

3.py:0.7s

4.py:0.7s

5.py:1.0s

以为我会得到与 1.py 类似的东西但它要快得多。

解决方案 6:

人们出于exec安全原因发出警告,但这是一个理想情况。

这是一个简单的状态机。

Codes = {}
Codes [0] = compile('blah blah 0; nextcode = 1')
Codes [1] = compile('blah blah 1; nextcode = 2')
Codes [2] = compile('blah blah 2; nextcode = 0')

nextcode = 0
While True:
    exec(Codes[nextcode])

解决方案 7:

你可以通过使用字典和 lambda 函数来用 switch-case 类型模拟 if-elif-else

例如:

x = 5
y = 5
operator = 'add'

def operation(operator, x, y): 
 return {
   'add': lambda: x+y,
   'sub': lambda: x-y,
   'mul': lambda: x*y,
   'div': lambda: x/y
 }.get(operator, lambda: None)()

result = operation(operator, x, y)
print(result)

解决方案 8:

最近我偶然发现了一种替代“嵌套 if else”的方法,它将我的函数的运行时间从 2.5 小时缩短至约 2 分钟。Baam!让我们开始吧:

早期代码

bin = lambda x:“Unknown” if x==0 else(“High” if x>75 else(“Medium” if x>50 and x<=75 else(“Medium_Low” if x>25 and x<=50 else “Low”)))

col.apply(bin) 时间~2.5小时

优化代码

定义嵌套 if else 的字典替代方法

 def dict_function(*args):
'Pass in a list of tuples, which will be key/value pairs'
ret = {}
for k,v in args:
    for i in k:
        ret[i] = v
return ret
Dict = dict_function(([0],"Unknown"),(range(1,25),"Low"),(range(25,50),"Medium_Low"),(range(50,75),"Medium"),(range(75,100),"High"))

col.apply(lambda x:Dict[x])

dict_function 根据给定范围生成多个键值对。时间~2 分钟

解决方案 9:

我最近遇到了同样的问题,虽然与性能无关,但我不喜欢创建函数并手动将它们添加到字典的“API”。我想要一个类似于的 API functools.singledispatch,但根据值而不是类型进行调度。所以...

def value_dispatch(func):
    """value-dispatch function decorator.
    Transforms a function into a function, that dispatches its calls based on the
    value of the first argument.
    """
    funcname = getattr(func, '__name__')
    registry = {}

    def dispatch(arg):
        """return the function that matches the argument"""
        return registry.get(arg, func)

    def register(arg):
        def wrapper(func):
            """register a function"""
            registry[arg] = func
            return func
        return wrapper

    def wrapper(*args, **kwargs):
        if not args:
            raise ValueError(f'{funcname} requires at least 1 positional argument')
        return dispatch(args[0])(*args, **kwargs)

    wrapper.register = register
    wrapper.dispatch = dispatch
    wrapper.registry = registry
    return wrapper

使用方式如下:

@value_dispatch
def handle_something():
    print("default")

@handle_something.register(1)
def handle_one():
    print("one")

handle_something(1)
handle_something(2)

PS:我在 Gitlab 上创建了一个代码片段,供参考

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2545  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1551  
  建筑工程全生命周期涉及从项目规划、设计、施工到运营维护等多个复杂阶段,每个阶段都产生和依赖大量信息。PLM(产品生命周期管理)系统作为一种整合数据、流程和人员的数字化解决方案,正逐渐成为建筑行业实现高效协同与可持续发展的关键支撑。通过数字化转型,PLM系统能够优化各阶段的工作流程,提升项目整体质量和效率,为建筑工程的全...
plm是什么软件   1  
  产品生命周期管理(PLM)系统在企业资源成本率优化方面发挥着至关重要的作用。通过构建有效的数据模型,PLM系统能够整合企业各个环节的数据,为资源成本的精准分析和优化提供有力支持。这不仅有助于企业降低成本,还能提升产品质量和市场竞争力。PLM系统概述PLM系统是一种用于管理产品从概念设计到退役全生命周期过程中所有信息和流...
PLM项目管理软件   1  
  产品生命周期管理(PLM)系统在现代企业的产品研发、生产与管理过程中扮演着至关重要的角色。它整合了从产品概念设计到产品退役的全生命周期数据与流程,助力企业提升效率、降低成本并增强创新能力。随着技术的不断发展,到 2025 年,PLM 系统将具备一系列核心功能模块,这些模块将深度影响企业的运营与发展。产品数据管理模块产品...
plm是什么意思   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用