python while true_Python天坑系列(一):while 1比while True更快?

更多

0. 前言

前些天被Python的多线程坑了一把,因此产生了写一个《Python天坑系列》博客的想法,说说我碰到的那些Python的坑。

而天坑这个词呢,一方面指Python的坑,另一方面也说明本系列文章也是个坑,对于会写什么内容、有多少篇、多久更新一次、什么时间更新我都无法确定,哈哈(看,之前已经3个月没有更新过了!)。

本篇是系列的第一篇,讲的内容是Python的bool类型。

1. 前提

1.1 bool是int的子类

根据PEP285中Review部分第6条所述,bool类是从int类继承而来的,这样可以极大的简化实现(C代码中调用PyInt_Check()的地方仍将继续工作)。

1.2 Python2中True/False不是关键字,但Python3中是

我们可以导入keyword模块,来查看关键字:

keyword

Python

# Python2 关键字

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

1

2

3

4

5

# Python2 关键字

>>>importkeyword

>>>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不是关键字,因此我们可以对其进行任意的赋值:

Python2 True赋值

Python

>>> (1 == 1) == True

True

>>> True = "pythoner.com"

>>> (1 == 1) == True

False

1

2

3

4

5

>>>(1==1)==True

True

>>>True="pythoner.com"

>>>(1==1)==True

False

2. True + True = 2

由于bool是继承自int的子类,因此为了保证向下兼容性,在进行算术运算中,True/False会被当作int值来执行。

True + True = 2

Python

>>> True + True

2

>>> True - True

0

>>> True * True

1

>>> (True + True) > 1

True

>>> True + 5

6

>>> 1 / False

Traceback (most recent call last):

File "", line 1, in

ZeroDivisionError: integer division or modulo by zero

1

2

3

4

5

6

7

8

9

10

11

12

13

14

>>>True+True

2

>>>True-True

0

>>>True*True

1

>>>(True+True)>1

True

>>>True+5

6

>>>1/False

Traceback(mostrecentcalllast):

File"",line1,in

ZeroDivisionError:integerdivisionormodulobyzero

3. While 1比While True快?

首先来看一个比较while 1和while True循环的脚本,两个函数中,除了1和True的区别之外,其他地方完全相同。

while 1与while True比较

Python

#! /usr/bin/python

# -*- coding: utf-8 -*-

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__":

w1 = 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" % (w1, wt)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

#! /usr/bin/python

# -*- coding: utf-8 -*-

importtimeit

defwhile_one():

i=0

while1:

i+=1

ifi==10000000:

break

defwhile_true():

i=0

whileTrue:

i+=1

ifi==10000000:

break

if__name__=="__main__":

w1=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"%(w1,wt)

执行结果:

while one: 1.37000703812

while_true: 2.07638716698

可以看出wihle 1的执行时间约为while True的2/3。

那么,这是为什么呢?

其实这就是前提中提到的关键字的问题。由于Python2中,True/False不是关键字,因此我们可以对其进行任意的赋值,这就导致程序在每次循环时都需要对True/False的值进行检查;而对于1,则被程序进行了优化,而后不会再进行检查。

我们可以通过dis模块来查看while_one和while_true的字节码,下面的程序是对刚才的程序进行了一定的简化后的版本。

while 1和while True的字节码程序

Python

#! /usr/bin/python

# -*- coding: utf-8 -*-

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

18

19

#! /usr/bin/python

# -*- coding: utf-8 -*-

importdis

defwhile_one():

while1:

pass

defwhile_true():

whileTrue:

pass

if__name__=="__main__":

print"while_one\n"

dis.dis(while_one)

print"while_true\n"

dis.dis(while_true)

执行的结果是:

while 1和while True的字节码执行结果

Python

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

while_one

60SETUP_LOOP3(to6)

7>>3JUMP_ABSOLUTE3

>>6LOAD_CONST0(None)

9RETURN_VALUE

while_true

100SETUP_LOOP10(to13)

>>3LOAD_GLOBAL0(True)

6POP_JUMP_IF_FALSE12

119JUMP_ABSOLUTE3

>>12POP_BLOCK

>>13LOAD_CONST0(None)

16RETURN_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,那么程序的执行效率又如何呢?

if x == True:和if x:比较

Python

#! /usr/bin/python

# -*- coding: utf-8 -*-

import timeit

def if_x_eq_true():

x = True

if x == True:

pass

def if_x():

x = True

if x:

pass

if __name__ == "__main__":

if1 = timeit.timeit(if_x_eq_true, "from __main__ import if_x_eq_true", number = 1000000)

if2 = timeit.timeit(if_x, "from __main__ import if_x", number = 1000000)

print "if_x_eq_true: %s\nif_x: %s" % (if1, if2)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#! /usr/bin/python

# -*- coding: utf-8 -*-

importtimeit

defif_x_eq_true():

x=True

ifx==True:

pass

defif_x():

x=True

ifx:

pass

if__name__=="__main__":

if1=timeit.timeit(if_x_eq_true,"from __main__ import if_x_eq_true",number=1000000)

if2=timeit.timeit(if_x,"from __main__ import if_x",number=1000000)

print"if_x_eq_true: %s\nif_x: %s"%(if1,if2)

执行结果是:

if_x_eq_true: 0.212558031082

if_x: 0.144327878952

让我们再来看看字节码(程序未作修改,dis的使用方式同上,因此不再给出程序):

if x == True:和if x:的字节码

Python

if_x_eq_true

8 0 LOAD_GLOBAL 0 (True)

3 STORE_FAST 0 (x)

9 6 LOAD_FAST 0 (x)

9 LOAD_GLOBAL 0 (True)

12 COMPARE_OP 2 (==)

15 POP_JUMP_IF_FALSE 21

10 18 JUMP_FORWARD 0 (to 21)

>> 21 LOAD_CONST 0 (None)

24 RETURN_VALUE

if_x

13 0 LOAD_GLOBAL 0 (True)

3 STORE_FAST 0 (x)

14 6 LOAD_FAST 0 (x)

9 POP_JUMP_IF_FALSE 15

15 12 JUMP_FORWARD 0 (to 15)

>> 15 LOAD_CONST 0 (None)

18 RETURN_VALUE

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

if_x_eq_true

80LOAD_GLOBAL0(True)

3STORE_FAST0(x)

96LOAD_FAST0(x)

9LOAD_GLOBAL0(True)

12COMPARE_OP2(==)

15POP_JUMP_IF_FALSE21

1018JUMP_FORWARD0(to21)

>>21LOAD_CONST0(None)

24RETURN_VALUE

if_x

130LOAD_GLOBAL0(True)

3STORE_FAST0(x)

146LOAD_FAST0(x)

9POP_JUMP_IF_FALSE15

1512JUMP_FORWARD0(to15)

>>15LOAD_CONST0(None)

18RETURN_VALUE

可以清晰的看到第9行比第14行,多出了检查True值和进行比较的操作。

也就是说,不论从遵循PEP的规范,还是执行效率,或者程序的简洁性来说,我们都应该使用if x:,而不是if x == True:来进行比较。同理,那些if x is not None:之类的语句也应当被简化为if x:(如果要比较的是非值,而不必须是None的话)。

5. References

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/505085.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

下列不属于PHP开发优势的是,php开发的优势有哪些?

说到PHP,好多刚刚毕业的学生都不是非常了解。这里,达内PHP培训老师跟大家分析一下目前行业中对这个技术方向的需求及发展情况。由于大学学科设置的问题,更多的学生都对C,C,Java等计算机语言比较熟悉,同时也…

苹果sf字体_苹果UI设计的改变意味着什么?

WWDC虽然已经过去了一段时间,虽然没有什么硬件产品,但还是给我们带来了许多新的惊喜。但我们这篇文章不谈技术问题,只谈苹果的UI变化。因为这可能是近10年来苹果第二次颠覆性的升级,上次还是2013年的iOS7的全面扁平化。从设计的层…

python需要配置环境变量吗_python安装和配置环境变量

Python 安装和配置环境变量 一、 Python 的安装: 在网上找一个 python 的安装包,我找的 python3.3.5 。照着安装步骤一步一步进行安装,完 成后,运行 IDLE(Python GUI) ,打开的命令行框出现类似如下内容则说明安装成功&…

python的tkinter按钮大小_如何使用python更改tkinter中按钮和帧的字体和大小?

更新:新墨西哥州科技tkinter网站已在GitHub上存档。必须有Tkinter对象才能创建字体from Tkinter import *import tkFontroot Tk()创建一个类似新墨西哥科技网站示例的字体helv36 tkFont.Font(familyHelvetica, size36, weightbold)# you dont have to use Helveti…

linux命令 翻译,(翻译)Linux命令行(一)

这里的Linux命令行系列是翻译自http://www.linuxguide.it/的,如果你英语够好,推荐你去看原版的。这是第一篇,主要介绍关机重启等操作和查看系统信息等操作的命令。关机重启等操作shutdown -h now 关机init 0 …

cuda卸载_Ubuntu18.04英伟达显卡驱动、Cuda安装

一、显卡驱动安装1. 准备工作禁用BIOS中的secure boot,因为此方法使用第三方源安装显卡驱动,不禁止secure boot会导致安装的驱动不能使用,禁用也不会有多大安全隐患。2. 禁用nouveau禁用nouveau,这是ubuntu默认使用的开源显卡驱动…

git两个账号切换_多个git账号之间的切换

$ clip < ~/.ssh/id_rsa.pubbash: /c/Users/UsersName/.ssh/id_rsa.pub: No such file or directoryStep 1、检查本机现有的SSH密钥检查~/.ssh看看是否有名为d_rsa.pub和id_dsa.pub的2个文件。如果你什么都没得到这些文件&#xff0c;转到 步骤2 ;否则&#xff0c;请跳到 …

linux服务器配置试卷,2016年Linux认证模拟练习题及答案

2016年Linux认证模拟练习题及答案1.设计一个shell程序&#xff0c;在每月第一天备份并压缩/etc目录的所有内容&#xff0c;存放在/root/bak目录里&#xff0c;且文件名为如下形式yymmdd_etc&#xff0c;yy为年&#xff0c;mm为月&#xff0c;dd为日。Shell程序fileback存放在/u…

内存条能4+8混插吗?_笔记本内存条双通道提升有多大?实测FORESEE,你知道好处在哪吗...

不知道大家发现了没&#xff0c;最近存储类产品、内存条普遍价格都涨起来了&#xff0c;后悔年前没买内存条给我的暗夜精灵3升升级&#xff0c;至今还插着一根8G的条子&#xff0c;其实日常用也够了。不过&#xff0c;今年打算做做视频&#xff0c;搞搞线上直播&#xff0c;所以…

python计算期望值_机器学习:计算方差时为何除以n-1

小弟准备了数据结构、Java、大数据、AI、面试题、python等各种资料 需要领取等朋友麻烦 转发此文&#xff0c;然后私信【学习】即可获取设样本均值为​&#xff0c;样本方差为​&#xff0c;总体均值为​&#xff0c;总体方差为​&#xff0c;那么样本方差​有如下公式&#xf…

linux rpm版本号,linux中RPM包命名规则

RPM包的一般格式为&#xff1a;name-version-arch.rpmname-version-arch.src.rpm例&#xff1a;httpd-2.2.3-29.el5.i386.rpmhttpd-devel-2.2.3-29.el5.i386.rpmhttpd-manual-2.2.3-29.el5.i386.rpmsystem-config-httpd-1.3.3.3-1.el5.noarch.rpm(1)name&#xff0c;如&#xf…

python十点半游戏代码_Python实现Pig Latin小游戏实例代码

前言&#xff1a; 本文研究的主要是Python实现pig Latin小游戏的简单代码&#xff0c;具体介绍如下。 Pig Latin是一个语言游戏。 步骤&#xff1a; 1.让用户输入一个英文单词 2.确保用户输入一个有效单词 3.将单词转换成Pig Latin 4.显示转换结果 一、Input 函数&#xff1a;r…

查看linux系统的sp,查看linux系统版本命令

一。查看内核版本命令&#xff1a;1) [[email protected]_SYS ~]# cat /proc/versionLinux version 2.6.18-238.el5 ([email protected]) (gcc version 4.1.2 20080704 (Red Hat 4.1.2-50)) #1 SMP Sun Dec 19 14:22:44 EST 20102)[[email protected]_SYS ~]# uname -r2.6.18-2…

程序的图标无法改变_安卓微信7.0.7内测版发布,细节更新,小程序功能优化

昨天&#xff0c;微信 7.0.7 for Android 内测版悄然发布&#xff0c;如何参加内测可以咨询本人。按照近来的惯例&#xff0c;安卓的内测版的功能会在随后的更新iOS正式版中体现&#xff0c;并且要先于安卓正式版发布。下面我们就来简单介绍一下本次更新的具体内容。一、「…」…

vue获取input的属性_vuejs 中如何优雅的获取 Input 值

原生 js使用 getElementById 比较麻烦的地方需要为元素设置 id设置 id 之后&#xff0c;无法复用&#xff0c;因为一个页面中不能存在两个相同的 id双向绑定 v-model分两种情况input 默认为空。这种情况使用 v-model 最方便&#xff0c;通过 this.inputName 即可获取到对应的值…

linux设置系统自动开机,Linux系统中设置开机自动运行的两种方法

有时可能会需要在重启时或者每次系统启动时运行某些命令或者脚本。我们要怎样做呢&#xff1f;本文中我们就对此进行讨论。 我们会用两种方法来描述如何在 CentOS/RHEL 以及 Ubuntu 系统上做到重启或者系统启动时执行命令和脚本。 两种方法都通过了测试。方法 1 – 使用 rc.loc…

论文页眉奇偶页不同怎么设置_怎样设置Word页眉页脚奇偶页不同?

来自Excel之家&#xff0c;侵联系删有伙伴问&#xff0c;怎么设置满足下列要求的页眉页脚&#xff1a;页眉要求正文部分偶数页居中对齐为“XXXX毕业设计(论文)”&#xff0c;奇数页居中对齐是各章章名&#xff1b;字体采用宋体5号。页眉之下有一条下划线。封面和目录页没有页眉…

layui添加复选框_layui复选框使用介绍

layui复选框&#xff1a;效果图layui复选框&#xff0c;一个主的复选框控制多个从复选框&#xff0c;主复选框和从复选框的颜色不一样layui复选框的样式&#xff0c;都是在选然后才会有的&#xff0c;所以直接通过css设置就实现不了了。只可以通过js动态设置html代码使用了jfin…

如何检测python是否安装_使用Python检查系统中是否安装了一个软件包?

How can I check is some package is installed in my system. My system is Linux, but even better if it could works in other OSs. I mean OS specific package (like could be *.rpm or *.deb). Is there any python module or script that could do it? 解决方案 To fi…

git进入项目目录 windows_Git使用教程 Windows使用Git全攻略

在Windows上安装Git点击Download开始下载&#xff0c;下载完成后双击安装包进行安装&#xff0c;之后一直点击“下一步”就可以完成安装了。创建代码仓库首先配置一下身份&#xff0c;这样在提交代码的时候Git就可以知道是谁提交的了。打开Git Bash&#xff0c;输入下面的命令g…