我们可以导入keyword模块,来查看关键字:
>>> import keyword >>> keyword.kwlist ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield']
而在Python3中,关键字中添加了True/False/None。
由于Python2中True/False不是关键字,因此我们可以对其进行任意的赋值:
>>> (1==1) == True True >>> True = "abc" >>> (1==1) == True False
2. True + True = 2
由于bool是继承自int的子类,因此为了保证向下兼容性,在进行算术运算中,True/False会被当作int值来执行。
>>> True + True 2 >>> True - True 0 >>> True * True 1 >>> (True + True) > 1 True >>> True + 5 6 >>> False + 1 1 >>> 1 / False Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: integer division or modulo by zero
3. While 1比While True快?
首先来看一个比较while 1和while True循环的脚本,两个函数中,除了1和True的区别之外,其他地方完全相同。
import timeit def while_one(): i = 0 while 1: i += 1 if i == 10000000: break def while_true(): i = 0 while True: i += 1 if i == 10000000: break if __name__ == '__main__': wone = timeit.timeit(while_one,"from __main__ import while_one",number=3) wt = timeit.timeit(while_true,"from __main__ import while_true",number=3) print "while_one: %s\nwhile_true: %s" % (wone,wt)
执行结果:
while_one: 0.937821149826
while_true: 1.39164209366
可以看出wihle 1的执行时间约为while True的2/3
那么,这是为什么呢?
其实这就是前提中提到的关键字的问题。由于Python2中,True/False不是关键字,因此我们可以对其进行任意的赋值,这就导致程序在每次循环时都需要对True/False的值进行检查;而对于1,则被程序进行了优化,而后不会再进行检查。
我们可以通过dis模块来查看while_one和while_true的字节码,下面的程序是对刚才的程序进行了一定的简化后的版本
import dis def while_one(): while 1: pass def while_true(): while True: pass if __name__ == "__main__": print "while_one\n" dis.dis(while_one) print "while_true\n" dis.dis(while_true)
执行的结果是:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
while_one
6
0
SETUP_LOOP
3
(to
6
)
7
>>
3
JUMP_ABSOLUTE
3
>>
6
LOAD_CONST
0
(
None
)
9
RETURN_VALUE
while_true
10
0
SETUP_LOOP
10
(to
13
)
>>
3
LOAD_GLOBAL
0
(
True
)
6
POP_JUMP_IF_FALSE
12
11
9
JUMP_ABSOLUTE
3
>>
12
POP_BLOCK
>>
13
LOAD_CONST
0
(
None
)
16
RETURN_VALUE
|
可以看出,正如上面所讲到的,在while True的时候,字节码中多出了几行语句,正是这几行语句进行了True值的检查。
而在Python3中,由于True/False已经是关键字了,不允许进行重新赋值,因此,其执行结果与while 1不再有区别(好吧,我这没有Python3的环境,就不去验证了,网上有人验证过了)。但是由于Python2的使用十分广泛,因此大家不得不注意这个可能会降低性能的地方。
4. if x == True: 还是 if x:
在PEP285中,还提到了这两种写法的比较。PEP285中认为,==
具有传递性,a==b, b==c会被化简为a==c。也就是说,如果选择前一种写法的话,6和7在if语句中都应该被认为是真值,那么就会造成6==True==7,被化简为6==7的问题,因此后一种写法才是正确的。
现在,让我们偏个题,假设x就是True,那么程序的执行效率又如何呢?
import timeit def if_x_equal_true(): x = True if x == True: pass def if_x(): x = True if x: pass if __name__ == "__main__": if1 = timeit.timeit(if_x_equal_true,"from __main__ import if_x_equal_true",number = 1000000) if2 = timeit.timeit(if_x,"from __main__ import if_x",number = 1000000) print "if_x_equal_true: %s\nif_x: %s" % (if1,if2)
执行结果:
if_x_equal_true: 0.127066850662
if_x: 0.0872008800507
让我们再来看看字节码(程序未作修改,dis的使用方式同上,因此不再给出程序):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
if_x_equal_true
7
0
LOAD_GLOBAL
0
(
True
)
3
STORE_FAST
0
(x)
8
6
SETUP_LOOP
16
(to
25
)
>>
9
LOAD_FAST
0
(x)
12
LOAD_GLOBAL
0
(
True
)
15
COMPARE_OP
2
(
=
=
)
18
POP_JUMP_IF_FALSE
24
9
21
JUMP_ABSOLUTE
9
>>
24
POP_BLOCK
>>
25
LOAD_CONST
0
(
None
)
28
RETURN_VALUE
if_x
12
0
LOAD_GLOBAL
0
(
True
)
3
STORE_FAST
0
(x)
13
6
SETUP_LOOP
10
(to
19
)
>>
9
LOAD_FAST
0
(x)
12
POP_JUMP_IF_FALSE
18
14
15
JUMP_ABSOLUTE
9
>>
18
POP_BLOCK
>>
19
LOAD_CONST
0
(
None
)
22
RETURN_VALUE
|
可以清晰的看到第9行比第14行,多出了检查True值和进行比较的操作。
也就是说,不论从遵循PEP的规范,还是执行效率,或者程序的简洁性来说,我们都应该使用if x:,而不是if x == True:来进行比较。同理,那些if x is not None:之类的语句也应当被简化为if x:(如果要比较的是非值,而不必须是None的话)。