Python while 1 和 while True 速度比较
References
http://legacy.python.org/dev/peps/pep-0285/
http://stackoverflow.com/questions/3815359/while-1-vs-for-whiletrue-why-is-there-a-difference
1. 前提
1.1 bool是int的子类
根据PEP285中Review部分第6条所述,bool类是从int类继承而来的,这样可以极大的简化实现(C代码中调用PyInt_Check()的地方仍将继续工作)。
1.2 Python2中True/False不是关键字,但Python3中是
我们可以导入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)
执行的结果是:
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的使用方式同上,因此不再给出程序):
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的话)。
Python while 1 和 while True 速度比较的更多相关文章
- Python:游戏:测试打字速度
现在写书的人真是一点责任心都没有,最近看了几本书,其中的代码都存在错误. 最近迷恋 Python 游戏,买了<Python游戏编程入门>[美] Jonathan S·Harbour 著 一 ...
- 【Python】xlrd,NotImplementedError-formatting_info=True not yet implemented
前言 Python需要读取Excel(.xls..xlsx)时通常使用xlrd模块:如果要对其内容进行编辑的话稍稍有些麻烦,通常的做法是使用xlutils的copy模块对原文件进行复制,然后保存成新的 ...
- python Thread对象的setDaemon(True)的作用。
1.如果主线程是永远都不会结束的,那设置一个线程为守护线程是没必要的,设不设置都一样. 2.什么时候需要设置为守护线程?如果希望子线程一直运行,可以把子线程的代码写在while True里面一直循环, ...
- 更换镜像加快python pip 安装扩展库的速度
一些镜像源: 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/ 阿里云 http://mirrors.aliyun.com/pypi/simple/ 中国科 ...
- python守护线程t.setDaemon(True)
守护线程是守护主线程 t.setDaemon(True),调用函数里面存在等待时间时,只要设置了守护线程,函数中等待时间下面的代码都不会再执行
- Python中查找字符串方法的速度比较
- windows下python自带的pip安装速度过慢解决方案
自带下载地址为国外源下载速度时常在20KB以内切换为国内源直接满速! 国内源: 新版ubuntu要求使用https源,要注意. 清华:https://pypi.tuna.tsinghua.edu.cn ...
- Python转载
让Python的经验更多一点 Python while 1 和 while True 速度比较 Python %s和%r的区别
- python 字典dict和列表list的读取速度问题, range合并
python 字典和列表的读取速度问题 最近在进行基因组数据处理的时候,需要读取较大数据(2.7G)存入字典中,然后对被处理数据进行字典key值的匹配,在被处理文件中每次读取一行进行处理后查找是否在字 ...
随机推荐
- c++学习笔记之基础---类内声明函数后在类外定义的一种方法
在C++的“类”中经常遇到这样的函数, 返回值类型名 类名::函数成员名(参数表){ 函数体.} 双冒号的作用 ::域名解析符!返回值类型名 类名::函数成员名(参数表) { 函数体. } 这个是在类 ...
- DRF之视图组件 三次封装
1.为什么要进行封装 1.1 在处理表的时候,如果有几十张表都需要增删改查查时,如果每一张表都写这些方法,会让代码显得冗余,所以需要将这些方法进行封装,然后不同的表都去继承这写方法.(这是思路) 1. ...
- sanic官方文档解析之蓝图
1,蓝图(Blueprints) 蓝图可用于子路由的应用,代替增加路由的存在,蓝图的定义和增加路由的方法相似,灵活的在应用中注册,并且可插拔的方式. 尤其是在大型应用中使用蓝图的时候在你逻辑打断的地方 ...
- sanic官方文档解析之logging和request Data
1,sanic的logging: Sanic允许有做不同类型的日志(通过的日志,错误的日志),在基于Python3的日志API接口请求,你必须具备基本的Python3的日志知识,在你如果想创建一个新的 ...
- UI类继承关系图
- 答案{{index==0 ? '一' : (index==1 ? '二':'三' )}}
答案{{index==0 ? '一' : (index==1 ? '二':'三' )}}
- XML-RPC JSON-RPC RPC是实现思路
XML-RPC - Wikipedia https://en.wikipedia.org/wiki/XML-RPC JSON-RPC - Wikipedia https://en.wikipedia. ...
- 5.3linux下C语言socket网络编程简例
原创文章,转载请注明转载字样和出处,谢谢! 这里给出在Linux下的简单socket网络编程的实例,使用tcp协议进行通信,服务端进行监听,在收到客户端的连接后,发送数据给客户端:客户端在接受到数据后 ...
- POJ - 2417 Discrete Logging(Baby-Step Giant-Step)
d. 式子B^L=N(mod P),给出B.N.P,求最小的L. s.下面解法是设的im-j,而不是im+j. 设im+j的话,貌似要求逆元什么鬼 c. /* POJ 2417,3243 baby s ...
- hdu2544 迪杰斯特拉题目优化
点击打开题目链接 迪杰斯特拉的用法不多讲,详见 点击打开链接 . 下面两个代码: 这个是用邻接矩阵存图的迪杰斯特拉. #include<stdio.h> int main() { int ...