简体   繁体   English

python中if语句的性能

[英]The performance about if statements in python

I prefer to assign conditions to variables when I have to write a long if statement. 当我不得不编写一个长的if语句时,我更喜欢为变量分配条件。

But when the conditions are time-wasting, I think it is not good because the interpreter should run all the conditions even if just few conditions should be run. 但是,当这些条件浪费时间时,我认为这是不好的,因为即使只运行少数条件,解释器仍应运行所有条件。

In the codes below for example, the test1 is more readable but slower than test2 because con1 is True and test2 just run only one condition. 例如,在下面的代码中, test1test2更具可读性,但速度较慢,因为con1Truetest2仅运行一个条件。

(I know the logic is ugly, because it is just for example) (我知道逻辑很难看,因为它只是举例)

def x(arg):
    '''
    A time-wasting method
    '''
    res = 0
    for i in range(2000000):
        res += i * arg
    return res

def test1():
    con1 = x(1) > 1000.24
    con2 = x(2) < 2000
    con3 = x(3) < 3000
    con4 = x(4) < 4000
    con5 = x(5) < 555
    con6 = x(6) < 666
    con7 = x(7) < 777
    con8 = x(8) < 888
    con9 = x(9) < 234
    con10 = x(10) < 345
    con11 = x(11) < 456
    con12 = x(12) < 445
    con13 = x(13) < 745
    con14 = x(14) < 3475
    con15 = x(15) < 334545
    con16 = x(16) < 323445
    con17 = x(17) < 37645
    con18 = x(18) < 3445
    con19 = x(19) < 37745
    con20 = x(20) < 3455

    if con1 or con2 or con3 or con4 or con5 or con6 or con7 or con8 or con9 or \
       con10 or con11 or con12 or con13 or con14 or con15 or con16 or con17 or \
       con18 or con19 or con20:
        print('test1')

def test2():
    if x(1) > 1000.24 or x(2) < 2000 or x(3) < 3000 or x(4) < 4000 or x(5) < 555 or \
       x(6) < 666 or x(7) < 777 or x(8) < 888 or x(9) < 234 or x(10) < 345 or \
       x(11) < 456 or x(12) < 445 or x(13) < 745 or x(14) < 3475 or x(15) < 334545 or \
       x(16) < 323445 or x(17) < 37645 or x(18) < 3445 or x(19) < 37745 or x(20) < 3455:
        print('test2')

What is the best way to deal with that? 最好的解决方法是什么?

Whenever you have a long list of or statements, you probably want to formulate those conditions as a list of uniform predicates and use any . 每当您的or语句列表很长时,您可能希望将这些条件表述为统一谓词列表,并使用any Eg: 例如:

predicates = [
    (2, 2000),
    (3, 3000),
    ...
]

if x(1) > 1000.24 or any(x(y) < z for y, z in predicates):
    ...

In this case all but the first case differ only in the specific numbers used, so writing them this way is the most compact. 在这种情况下,除了第一种情况外,其他所有区别仅在于所使用的特定数字,因此以这种方式编写它们是最紧凑的。 You can of course also use a list of callables, which can do anything you need: 当然,您也可以使用可调用对象列表,它可以完成您需要执行的任何操作:

from functools import partial

predicates = [
    lambda: x(1) > 1000.24,
    lambda: x(2) < 2000,
    ...
    partial(sum, range(42)),
    ...
]

if any(p() for p in predicates):
    ...

Use any when you need to lazily or multiple expressions. 当您需要懒惰or多个表达式时,请使用any You can feed it with a generator that goes through the parameters of comparison: 您可以通过比较参数生成器来提供它:

test_parameters = ((2, 2000), (3, 3000), (4, 4000), (5, 555))

if x(1) < 1000.24 or any(x(a) > b for a, b in test_parameters):
   ...

You can also use all to and expressions. 您也可以使用all to and表达式。

We can use containers and any function here like 我们可以在这里使用容器和any函数

from operator import gt, lt

def test3():
    domain = range(1, 21)
    predicates_with_bounds = [(gt, 1000.24),
                              (lt, 2000),
                              (lt, 3000),
                              (lt, 4000),
                              (lt, 555),
                              (lt, 666),
                              (lt, 777),
                              (lt, 888),
                              (lt, 234),
                              (lt, 345),
                              (lt, 456),
                              (lt, 445),
                              (lt, 745),
                              (lt, 3475),
                              (lt, 334545),
                              (lt, 323445),
                              (lt, 37645),
                              (lt, 3445),
                              (lt, 37745),
                              (lt, 3455)]
    if any(predicate(x(element), bound)
           for element, (predicate, bound) in zip(domain,
                                                  predicates_with_bounds)):
        print('test3')

or by "switching" < -> > and using functools.partial we can make container of predicates with bounds bounded (sorry for pun) 或通过“开关” < - > >并使用functools.partial我们可以使谓词的容器与边界为界(抱歉双关语)

from functools import partial
from operator import gt, lt

def test4():
    domain = range(1, 21)
    predicates = [partial(lt, 1000.24),
                  partial(gt, 2000),
                  partial(gt, 3000),
                  partial(gt, 4000),
                  partial(gt, 555),
                  partial(gt, 666),
                  partial(gt, 777),
                  partial(gt, 888),
                  partial(gt, 234),
                  partial(gt, 345),
                  partial(gt, 456),
                  partial(gt, 445),
                  partial(gt, 745),
                  partial(gt, 3475),
                  partial(gt, 334545),
                  partial(gt, 323445),
                  partial(gt, 37645),
                  partial(gt, 3445),
                  partial(gt, 37745),
                  partial(gt, 3455)]
    if any(predicate(x(element))
           for element, predicate in zip(domain, predicates)):
        print('test4')

Assign lambda expressions to the variables, so they aren't executed until you call them in the if statement. 将lambda表达式分配给变量,以便直到您在if语句中调用它们之后才执行它们。

def test1():
    con1 = lambda: x(1) > 1000.24
    con2 = lambda: x(2) < 2000
    con3 = lambda: x(3) < 3000
    ...

    if con1() or con2() or con3() or ...:
        print('test1')

But really I think you need to re-examine the logic of your program. 但实际上我认为您需要重新检查程序的逻辑。 Why does it need so many conditions in a single if statement? 为什么在一个if语句中需要这么多条件? Is there some pattern to it that you can extract to simplify it? 是否可以提取一些模式以简化它?

Another method would be to make a list that represents all the comparisons: 另一种方法是制作一个代表所有比较的列表:

cons = [('>', 1000.24), ('<', 2000), ('<', 3000), ...]
def test1():
    for i, test in enumerate(cons):
        if test[0] == '<':
            if x(i+1) < test[1]:
                print('test')
                break
        elif x(i+1) > test[1]:
            print('test')
            break

You can make it data driven with something like: 您可以通过以下方式使其成为数据驱动:

# Each item has index, less-than-value and greater-than-value.
data = [[1, None, 1000.24], [2, 2000, None], … [19, 37745, None], [20, 3455, None]]

outcome = False
for item in data:
    if item[1] is not None: outcome = outcome or x[item[0]] < item[1]
    if item[2] is not None: outcome = outcome or x[item[0]] > item[2]

# Outcome now contains result of all data driven comparisons, or'ed together.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM