python

时间:2019-06-08 05:11:22

标签: python

当我不得不写一个长的if语句时,我更喜欢为变量分配条件。

但是当条件很浪费时间时,我认为这不好,因为即使只运行少数条件,解释器也应运行所有条件。

例如,在以下代码中,test1test2更具可读性,但速度较慢,因为con1True,而test2仅运行一个条件

(我知道逻辑很丑,因为只是一个例子)

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')

最好的解决方法是什么?

5 个答案:

答案 0 :(得分:1)

每当有很长的or语句列表时,您可能希望将这些条件表述为统一谓词列表并使用any。例如:

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

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

在这种情况下,除了第一种情况外,其他所有区别仅在于所使用的特定数字,因此以这种方式编写它们是最紧凑的。当然,您也可以使用可调用对象列表,它可以完成您需要执行的任何操作:

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):
    ...

答案 1 :(得分:1)

当您需要延迟any多个表达式时,请使用or。您可以使用生成比较参数的生成器来填充它:

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):
   ...

您还可以使用alland表达式。

答案 2 :(得分:1)

我们可以在此处使用容器和any function

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')

或通过“切换” <-> >并使用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')

答案 3 :(得分:0)

将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')

但是实际上我认为您需要重新检查程序的逻辑。为什么在单个if语句中需要这么多条件?有没有可以提取出来以简化它的模式?

另一种方法是制作一个代表所有比较的列表:

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

答案 4 :(得分:0)

您可以通过以下方式使它成为数据驱动的

# 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.