更多

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 while_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 while_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 "

dis.dis(while_one)

print "while_true "

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 "

dis.dis(while_one)

print"while_true "

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 if_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 if_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

python while-Python天坑系列(一):while 1比while True更快?相关推荐

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

    更多 0. 前言 前些天被Python的多线程坑了一把,因此产生了写一个<Python天坑系列>博客的想法,说说我碰到的那些Python的坑. 而天坑这个词呢,一方面指Python的坑,另 ...

  2. python矩阵对角线求和numpy_以numpy计算对角线和(更快)

    使用stride_tricks有一个可能的解决方案.这在一定程度上是基于this question的答案中提供的大量信息,但我认为,问题只是不同而已,不算重复.这是一个基本思想,应用到一个方阵中,见下 ...

  3. python图片压缩算法_Optipng,jpegoptim应用,用python实现图片压缩,让你的网站变得更快...

    compress p_w_picpaths according to google suggestion. 1.环境:ubuntu12.04 . python 2.7.3 2.工具:optipng . ...

  4. 你知道python统计字符串中字符出现次数的方法中哪个更快吗?

    首先按照原来学习过的语言基础,想到如下代码: [方法一] str = input('input text:') # 保存已经检测过的字母 check = '' rec = [] # 从当前输入的字符串 ...

  5. python基础===Python 代码优化常见技巧

    Python 代码优化常见技巧 代码优化能够让程序运行更快,它是在不改变程序运行结果的情况下使得程序的运行效率更高,根据 80/20 原则,实现程序的重构.优化.扩展以及文档相关的事情通常需要消耗 8 ...

  6. python创建一个json_如何为Python选择一个更快的JSON库

    使用JSON越多, 你就越有可能遇到JSON编码或解码瓶颈.Python的内置库也不错, 但是还有多个更快的JSON库可用: 如何选择使用哪一个呢? 事实是,没有一个正确的答案,没有一个最快的JSON ...

  7. javascript python谁快,Python和JavaScript的速度哪个更快?

    不管你用的是什么代码,都很难避免最终出现优化问题.就像很多人所想的那样,从一天简单的开车到一台基本机器的机械结构,软件工程师们常常开始四处寻找解决问题的快捷方法. 设计出简约.高效.高效的软件,不仅是 ...

  8. python并行编程语言_Python3 系列之 并行编程

    Python Python开发 Python语言 Python3 系列之 并行编程 进程和线程 进程是程序运行的实例.一个进程里面可以包含多个线程,因此同一进程下的多个线程之间可以共享线程内的所有资源 ...

  9. 九十八、轻松搞定Python中的Markdown系列

    @Author:Runsen @Date:2020/7/15 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏 ...

最新文章

  1. installshield 安装文件属性的原始文件名 如何修改_iPhone修改微信提示音,iOS12可用,无需越狱详细教程...
  2. ios 状态蓝颜色控制
  3. Filter若不写chain.doFilter(request,response)原Servlet路径代码不会被执行
  4. 《看聊天记录都学不会C#?太菜了吧》(2)C#那么简单我为何之前还学C语言?
  5. Struts2基础知识(二)
  6. 动漫App下载单页界面HTML源码带弹幕
  7. 【树莓派】树莓派3B安装宝塔面板并配置安装LNMP
  8. C#LeetCode刷题之#242-有效的字母异位词(Valid Anagram)
  9. pwm控制舵机转动角度程序_舵机的内部结构及工作原理
  10. CGO磁盘管理For流星无语
  11. mysql简单部署_Docker部署简单的mysql
  12. 为什么科学家这么痴迷于研究僵尸?
  13. 人脸方向学习(十三):Face Tracking-人脸跟踪KCF解读
  14. 服务器经过交换机传递文件丢失,H3C交换机bin文件丢失后补救方案
  15. 吉林大学计算机学院刘衍衍教授,周柚-吉林大学计算机科学与技术学院
  16. FreeBSD tips
  17. 使用Apache commons-pool2实现高效的FTPClient连接池的方法
  18. 液压伺服控制技术和电液比例控制技术
  19. Tableau超市数据分析报告
  20. html注册页面教程视频,新手建站HTML 学习系列视频教程之HTML 简介

热门文章

  1. python tkinter控件_python GUI作业:使用tkinter的重要控件
  2. Jenkins构建自动化任务
  3. 多线程基础-基本概念(一)
  4. 算法训练营01-学习总览
  5. 深入理解弹性盒布局(fiex-box)——Web前端系列自学笔记
  6. C语言满分代码:L1-056 猜数字 (20分)
  7. L1-008 求整数段和(解题报告 C语言实现)(11行代码AC~!)
  8. 开关怎么使用_开关也能自发电?ebelong易百珑S2自发电无线开关曝光
  9. servlet中弹出网页对话框
  10. print在python2和python3的区别_Python2和Python3中print的不同点