在 Python 中不在一行中做一个简单的 if-else 语句是不好的做法吗?
Is it bad practice to make a simple if-else statement not on one single line in Python?
在实习期间,我注意到我的一位同事通过这样做操纵了我的一项职能:
if isSinglesMatch:
name1 = GetName(1, "BUG")
name2 = GetName(2, "BUG")
else:
name1 = GetName(1, "Short")
name2 = GetName(2, "Short")
对此:
name1 = GetName(1, "BUG" if isSinglesMatch else "Short")
name2 = GetName(2, "BUG" if isSinglesMatch else "Short")
我看到他的代码更短了,但是有没有解释速度更快的优点?保持它最初的样子不好吗?在我看来,调试我的代码更容易(我在这个例子中遗漏了一些额外的变量赋值)。
实习期间没有人告诉我应该改变做事的方式,我只是注意到我的同事喜欢这样做。
在我看来,两行相同的条件更糟糕。你的代码更容易理解。最好是:
mode = "BUG" if is_singles_match else "Short"
name1 = get_name(1, mode)
name2 = get_name(2, mode)
注意命名约定。
如果您对解释器的影响感到好奇,可以随时使用 dis
。我很好奇所以 运行 我自己:
我添加了一些序言只是为了定义 GetName
和 isSinglesMatch
,但这是您的示例的反汇编代码:
1 0 LOAD_CONST 0 (False)
2 STORE_NAME 0 (isSinglesMatch)
2 4 LOAD_CONST 1 (<code object GetName at 0x7f4e90337810, file "test_a.py", line 2>)
6 LOAD_CONST 2 ('GetName')
8 MAKE_FUNCTION 0
10 STORE_NAME 1 (GetName)
5 12 LOAD_NAME 0 (isSinglesMatch)
14 POP_JUMP_IF_FALSE 38
6 16 LOAD_NAME 1 (GetName)
18 LOAD_CONST 3 (1)
20 LOAD_CONST 4 ('BUG')
22 CALL_FUNCTION 2
24 STORE_NAME 2 (name1)
7 26 LOAD_NAME 1 (GetName)
28 LOAD_CONST 5 (2)
30 LOAD_CONST 4 ('BUG')
32 CALL_FUNCTION 2
34 STORE_NAME 3 (name2)
36 JUMP_FORWARD 20 (to 58)
9 >> 38 LOAD_NAME 1 (GetName)
40 LOAD_CONST 3 (1)
42 LOAD_CONST 6 ('Short')
44 CALL_FUNCTION 2
46 STORE_NAME 2 (name1)
10 48 LOAD_NAME 1 (GetName)
50 LOAD_CONST 5 (2)
52 LOAD_CONST 6 ('Short')
54 CALL_FUNCTION 2
56 STORE_NAME 3 (name2)
>> 58 LOAD_CONST 7 (None)
60 RETURN_VALUE
更简洁的版本:
1 0 LOAD_CONST 0 (False)
2 STORE_NAME 0 (isSinglesMatch)
2 4 LOAD_CONST 1 (<code object GetName at 0x7f13f8f1f810, file "test_a.py", line 2>)
6 LOAD_CONST 2 ('GetName')
8 MAKE_FUNCTION 0
10 STORE_NAME 1 (GetName)
5 12 LOAD_NAME 1 (GetName)
14 LOAD_CONST 3 (1)
16 LOAD_NAME 0 (isSinglesMatch)
18 POP_JUMP_IF_FALSE 24
20 LOAD_CONST 4 ('BUG')
22 JUMP_FORWARD 2 (to 26)
>> 24 LOAD_CONST 5 ('Short')
>> 26 CALL_FUNCTION 2
28 STORE_NAME 2 (name1)
6 30 LOAD_NAME 1 (GetName)
32 LOAD_CONST 6 (2)
34 LOAD_NAME 0 (isSinglesMatch)
36 POP_JUMP_IF_FALSE 42
38 LOAD_CONST 4 ('BUG')
40 JUMP_FORWARD 2 (to 44)
>> 42 LOAD_CONST 5 ('Short')
>> 44 CALL_FUNCTION 2
46 STORE_NAME 3 (name2)
48 LOAD_CONST 7 (None)
50 RETURN_VALUE
忽略 MAKE_FUNCTION/STORE_NAME
之前的所有内容,您会发现性能成本略有不同。但是,为了可读性,我个人会牺牲这种情况下的性能。
编程很自以为是,他这样做大概是有原因的。
一是为了可读性。很多时候,开发人员为了易于阅读而牺牲了微不足道的性能下降。如果您有易于阅读的代码,那么维护它就不会像难以阅读的那样痛苦。
我认为在这种情况下你必须问问你的同事。他们可能遵循一些您可能不熟悉的代码风格。
这不是一个坏习惯。这只是取决于你在哪里使用它。
我注意到几家公司采用相同的标准。通常,条件语句将被缩短为一行——通过三元运算符——因此代码看起来更简洁。
如果条件很简单,那就太好了。在您提供的示例中,修改后的代码更清晰,两个变量 name1
和 name2
仅声明一次。
虽然原始代码可以正常工作,但可以将修订版视为做同样事情的简化方式。
如果您想确定何时应该分解条件,请考虑是否可以将其编写得更简单(同时仍然可以理解)。如果它导致多个嵌套的三元运算符,在这种情况下最好避免它。
在实习期间,我注意到我的一位同事通过这样做操纵了我的一项职能:
if isSinglesMatch:
name1 = GetName(1, "BUG")
name2 = GetName(2, "BUG")
else:
name1 = GetName(1, "Short")
name2 = GetName(2, "Short")
对此:
name1 = GetName(1, "BUG" if isSinglesMatch else "Short")
name2 = GetName(2, "BUG" if isSinglesMatch else "Short")
我看到他的代码更短了,但是有没有解释速度更快的优点?保持它最初的样子不好吗?在我看来,调试我的代码更容易(我在这个例子中遗漏了一些额外的变量赋值)。
实习期间没有人告诉我应该改变做事的方式,我只是注意到我的同事喜欢这样做。
在我看来,两行相同的条件更糟糕。你的代码更容易理解。最好是:
mode = "BUG" if is_singles_match else "Short"
name1 = get_name(1, mode)
name2 = get_name(2, mode)
注意命名约定。
如果您对解释器的影响感到好奇,可以随时使用 dis
。我很好奇所以 运行 我自己:
我添加了一些序言只是为了定义 GetName
和 isSinglesMatch
,但这是您的示例的反汇编代码:
1 0 LOAD_CONST 0 (False)
2 STORE_NAME 0 (isSinglesMatch)
2 4 LOAD_CONST 1 (<code object GetName at 0x7f4e90337810, file "test_a.py", line 2>)
6 LOAD_CONST 2 ('GetName')
8 MAKE_FUNCTION 0
10 STORE_NAME 1 (GetName)
5 12 LOAD_NAME 0 (isSinglesMatch)
14 POP_JUMP_IF_FALSE 38
6 16 LOAD_NAME 1 (GetName)
18 LOAD_CONST 3 (1)
20 LOAD_CONST 4 ('BUG')
22 CALL_FUNCTION 2
24 STORE_NAME 2 (name1)
7 26 LOAD_NAME 1 (GetName)
28 LOAD_CONST 5 (2)
30 LOAD_CONST 4 ('BUG')
32 CALL_FUNCTION 2
34 STORE_NAME 3 (name2)
36 JUMP_FORWARD 20 (to 58)
9 >> 38 LOAD_NAME 1 (GetName)
40 LOAD_CONST 3 (1)
42 LOAD_CONST 6 ('Short')
44 CALL_FUNCTION 2
46 STORE_NAME 2 (name1)
10 48 LOAD_NAME 1 (GetName)
50 LOAD_CONST 5 (2)
52 LOAD_CONST 6 ('Short')
54 CALL_FUNCTION 2
56 STORE_NAME 3 (name2)
>> 58 LOAD_CONST 7 (None)
60 RETURN_VALUE
更简洁的版本:
1 0 LOAD_CONST 0 (False)
2 STORE_NAME 0 (isSinglesMatch)
2 4 LOAD_CONST 1 (<code object GetName at 0x7f13f8f1f810, file "test_a.py", line 2>)
6 LOAD_CONST 2 ('GetName')
8 MAKE_FUNCTION 0
10 STORE_NAME 1 (GetName)
5 12 LOAD_NAME 1 (GetName)
14 LOAD_CONST 3 (1)
16 LOAD_NAME 0 (isSinglesMatch)
18 POP_JUMP_IF_FALSE 24
20 LOAD_CONST 4 ('BUG')
22 JUMP_FORWARD 2 (to 26)
>> 24 LOAD_CONST 5 ('Short')
>> 26 CALL_FUNCTION 2
28 STORE_NAME 2 (name1)
6 30 LOAD_NAME 1 (GetName)
32 LOAD_CONST 6 (2)
34 LOAD_NAME 0 (isSinglesMatch)
36 POP_JUMP_IF_FALSE 42
38 LOAD_CONST 4 ('BUG')
40 JUMP_FORWARD 2 (to 44)
>> 42 LOAD_CONST 5 ('Short')
>> 44 CALL_FUNCTION 2
46 STORE_NAME 3 (name2)
48 LOAD_CONST 7 (None)
50 RETURN_VALUE
忽略 MAKE_FUNCTION/STORE_NAME
之前的所有内容,您会发现性能成本略有不同。但是,为了可读性,我个人会牺牲这种情况下的性能。
编程很自以为是,他这样做大概是有原因的。 一是为了可读性。很多时候,开发人员为了易于阅读而牺牲了微不足道的性能下降。如果您有易于阅读的代码,那么维护它就不会像难以阅读的那样痛苦。
我认为在这种情况下你必须问问你的同事。他们可能遵循一些您可能不熟悉的代码风格。
这不是一个坏习惯。这只是取决于你在哪里使用它。
我注意到几家公司采用相同的标准。通常,条件语句将被缩短为一行——通过三元运算符——因此代码看起来更简洁。
如果条件很简单,那就太好了。在您提供的示例中,修改后的代码更清晰,两个变量 name1
和 name2
仅声明一次。
虽然原始代码可以正常工作,但可以将修订版视为做同样事情的简化方式。
如果您想确定何时应该分解条件,请考虑是否可以将其编写得更简单(同时仍然可以理解)。如果它导致多个嵌套的三元运算符,在这种情况下最好避免它。