当我不得不写一个长的if语句时,我更喜欢为变量分配条件。
但是当条件很浪费时间时,我认为这不好,因为即使只运行少数条件,解释器也应运行所有条件。
例如,在以下代码中,test1
比test2
更具可读性,但速度较慢,因为con1
为True
,而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')
最好的解决方法是什么?
答案 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):
...
您还可以使用all
到and
表达式。
答案 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.