在某些编程语言中,例如 C/C++、C#、PHP、Java、JavaScript 等等,do-while 是一种基本的循环结构。

它的核心语义是:先执行一遍循环体代码,然后执行一遍条件语句,若条件语句判断为真,则继续执行循环体代码,并再次执行条件语句;直到条件语句判断为假,则跳出循环结构。

流程图如下(Java 示例):

// 打印小于 20 的数字
public class Test {
public static void main(String[] args){
int x = 10;
do {
System.out.print("value of x : " + x );
x++;
System.out.print("\n");
} while(x < 20);
}
}

Python 并不支持 do-while 结构,“do”并不是一个有效的关键字。

那么,为什么 Python 不提供这种语法结构呢,这种现状的背后有何种设计考量因素呢?

在回答这个问题之前,让我们再仔细思考一下 do-while 语法可以解决什么问题,看看使用这种结构能带来什么好处?

最显而易见的好处是:do-while 语法保证了会先执行一遍循环体代码。

它的使用场景也许不多,但是,跟普通的 while 循环或者 for 循环语法的“条件前置”思想不同,它体现的是一种“条件后置”的编程逻辑,也是一种控制循环的常见方式。

它们的关系似乎有点像 C/C++ 这些语言中的i++++i操作的区别,在某些特殊场合中,也许会更为高效。

除了这一特点,这种结构最大的应用场景其实是在 C/C++ 中特殊的do {...} while (0) 用法。这在很多开源项目的源码中都能找到踪迹,例如 Linux、Redis 以及 CPython 解释器,等等。

这里面的数字 0 表示布尔值 False,意味着循环只会执行一遍,然后就跳出。

这样的写法是不是很诡异?所谓“循环”,一般就意味着程序体会被反复执行多次,但是,do {...} while (0) 却偏偏只需要它执行一遍,这初看起来是有点多余啊。

这种写法主要用在宏函数的定义中,可以解决宏代码块的编译问题,使代码按照我们的意图而合理分块。

另外,do {...} while (0) 结合 break 使用,还可以实现很优雅的跳转控制效果。

在下面的示例中,步骤 1、4 和 5 要求必须执行,而步骤 2 取决于步骤 1 的执行结果,步骤 3 则取决于步骤 2 的执行结果。

do {
// 执行步骤 1
if (条件1失败) {
break;
}
// 执行步骤 2
if (条件2失败) {
break;
}
// 执行步骤 3
if (条件3失败) {
break;
}
} while(0);
// 执行步骤 4
// 执行步骤 5

在这种场景中,我们确实只需要按照顺序执行一遍。do-while 结构很清晰,避免造成多层条件嵌套或者设置诸多额外标记的局面。

最后还有一点,在汇编层面,do-while 比 while 更接近汇编语言的逻辑,可以节省使用指令,在过去的低内存时代,算得上是一种优化写法。

分析完 do-while 的好处后,让我们回到主题:Python 为什么不需要设计 do-while 循环语法呢?

首先,Python 离底层应用编程太远了,就不用考虑汇编指令的优化了,同时,它也不涉及宏的使用。

至于“条件前置”和“条件后置”的区别,其实并没有太大影响,而且,由于 Python 使用简洁优雅的缩进加冒号语法来划分代码块,导致直译过来的 do-while 语法看起来会很怪异(注意,直译的 while 的条件后没有其它内容):

do:
pass
while False

想要引入新的语法特性,必然要遵守既定的风格习惯。其它语言的 do-while 结构直译成 Python 的话,肯定不合适。

事实上,在 2003 年时,有一个 PEP 提议给 Python 加上 do-while 语法支持:

PEP-315 Enhanced While Loop

该 PEP 提议增加一个可选的 do 子句,支持将 while 循环扩展成这样子:

do:
<setup code>
while <condition>:
<loop body>

这不是简单地从其它语言翻译成 Python,它的 while 语句后保留了 Python 的缩进用法,并不会造成直译形式的突兀结果。

加上 while 循环本身已支持的可选的 else 子句,因此,while 完整的语法结构是这样的:

while_stmt : ["do" ":" suite]
"while" expression ":" suite
["else" ":" suite]

(PS.在本系列的下一篇文章,我们将解释为什么 Python 要支持 while-else 语法)

也就是说,在保持原 while 循环语法不变的情况下,PEP-315 提议支持在 while 前面使用一个可选的 do 子句。

do 子句只会执行一遍,当它里面出现 break 时,则跳出整个 do-while 循环;当 do 子句中出现 continue 时,则跳出 do 子句,进到 while 的条件判断中。

有了 do 子句后,很容易就能实现 do {...} while (0) 的跳转控制效果。

但是,这个 PEP 遭到了一些核心开发者的反对。

反对的理由是,不需要引入新的关键字和语法,仅使用现有语法就能很好地实现同样的功能:

while True:
<setup code>
if not <condition>:
break
<loop body>

Python 之父 Guido van Rossum 也持反对意见,他的原话是:

Please reject the PEP. More variations along these lines won't make the

language more elegant or easier to learn. They'd just save a few hasty

folks some typing while making others who have to read/maintain their code wonder what it means.

简单翻译一下,这种 do-while 语法并不会使 Python 更优雅好用,反而会产生阅读/维护代码的理解负担。

就个人的感觉而言,我也不赞成引入 PEP-315 那种可选的 do-while 语法,虽然它比固定形式的 do-while 结构更为灵活和优雅一点。

最后稍微总结一下,do-while 作为一种常见的循环结构,在其它语言中有所发挥,它甚至还发展出了 do {...} while (0) 的典型用法,但是,do-while 能够解决的几个问题要么在 Python 中并不存在(宏定义、汇编指令),要么就是已经有更为合适而低成本的实现(跳转控制)。

看完这篇文章,你是否还有其它补充的内容呢?欢迎交流讨论。

如果你对 Python 语言设计相关的话题感兴趣,欢迎订阅 Github 上的《Python为什么》系列文章(https://github.com/chinesehuazhou/python-whydo)

关联阅读:

Python 为什么会有个奇怪的“...”对象?

Python 函数为什么会默认返回 None?

Python 之父为什么嫌弃 lambda 匿名函数?

为什么继承 Python 内置类型会出问题?!

Python 为什么推荐蛇形命名法?

Python 为什么不设计 do-while 循环结构?的更多相关文章

  1. Python学习--04条件控制与循环结构

    Python学习--04条件控制与循环结构 条件控制 在Python程序中,用if语句实现条件控制. 语法格式: if <条件判断1>: <执行1> elif <条件判断 ...

  2. Python程序设计实验报告四:循环结构程序设计(设计型实验)

    安徽工程大学 Python程序设计 实验报告 班级   物流191   姓名  姚彩琴  学号3190505129 成绩 日期     2020.4.8     指导老师       修宇 [实验名称 ...

  3. PYTHON 100days学习笔记004:循环结构

    目录 Day04 - 循环结构 1. 循环结构的应用场景 2.for-in循环 3. while循环 4. 练习 4.1 输入一个数判断是不是素数. 4.2 输入两个正整数,计算最大公约数和最小公倍数 ...

  4. C语言入门7-程序设计方法基础-循环结构

    程序设计方法基础-循环结构 循环三要素: 初值   循环判断条件   步长(循环增量) 循环结构在有些书籍上也称为重复结构,  即反复执行某一部分的操作. 循环三要素: 初值   循环判断条件   步 ...

  5. python基础之循环结构以及列表

    python基础之编译器选择,循环结构,列表 本节内容 python IDE的选择 字符串的格式化输出 数据类型 循环结构 列表 简单购物车的编写 1.python IDE的选择 IDE的全称叫做集成 ...

  6. 第五篇:python基础之循环结构以及列表

    python基础之循环结构以及列表   python基础之编译器选择,循环结构,列表 本节内容 python IDE的选择 字符串的格式化输出 数据类型 循环结构 列表 简单购物车的编写 1.pyth ...

  7. python自学笔记10:while循环和for循环

    条件控制和循环控制是两种典型的流程控制方法,前面我们写了 if 条件控制,这节讲 for 循环和 while 循环. 循环是另一种控制流程的方式,一个循环体中的代码在程序中只需要编写一次,但可能会连续 ...

  8. python分支和循环结构

    本文收录在Python从入门到精通系列文章系列 1. 分支结构 1.1 应用场景 迄今为止,我们写的Python代码都是一条一条语句顺序执行,这种代码结构通常称之为顺序结构.然而仅有顺序结构并不能解决 ...

  9. python控制语句---循环结构语句

    这次主要把循环结构的控制语句补上,主要包含while.for.continue.break.循环嵌套.主要写一些基本的认识以及包含的一些实例.当只有唯一路径且只跑一次的时候选择上一节中的选择结构语句就 ...

随机推荐

  1. Qt-Vnc远程

    VNC简介 VNC(Virtual Network Computing)是基于RFB(Remote Frame Buffer)协议的远程系统,C/S端口默认为5900,B/S端口默认为5800. RF ...

  2. libevent源码学习(1):日志及错误处理

    目录 错误处理函数 函数声明 __attribute__指令 函数定义 可变参数宏 _warn_helper函数 日志处理 event_log日志处理入口 日志处理回调函数指针log_fn 设置日志处 ...

  3. JAVA提取字符串中所有的URL链接,并加上a标签

    工具类 Patterns.java 1 package com.util; 2 3 import java.util.regex.Matcher; 4 import java.util.regex.P ...

  4. c++11之find 和 find_if 和 find_if_not 用法

    时刻提醒自己 Note: vector的释放 0.头文件 #include <algorithm> 1.区别 返回范围 [first, last) 中满足特定判别标准的首个元素: 函数 功 ...

  5. 设计owllook网络小说推荐系统

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 数据 推荐算法 协同过滤 基于流行度的推荐 基于用户标签相似度的推荐 评价指标 算 ...

  6. hdu-5569matrix(dp)

    http://acm.hdu.edu.cn/showproblem.php?pid=5569; 题目意思: 从(1,1)点出发只能向右和向下走,到达(n,n)点时所得到的价值最小, 价值是Let th ...

  7. 带你熟悉鸿蒙轻内核Kconfig使用指南

    摘要:本文介绍了Kconfig的基础知识,和鸿蒙轻内核的图形化配置及进阶的使用方法. 本文分享自华为云社区<鸿蒙轻内核Kconfig使用笔记>,作者: zhushy. 1. Kconfig ...

  8. 一站式元数据治理平台——Datahub入门宝典

    随着数字化转型的工作推进,数据治理的工作已经被越来越多的公司提上了日程.作为新一代的元数据管理平台,Datahub在近一年的时间里发展迅猛,大有取代老牌元数据管理工具Atlas之势.国内Datahub ...

  9. uniapp使用uni.openDocument打开文件时,安卓打开成功,iOS打开失败【原因:打开的文件的文件名是中文】

    解决办法:使用escape进行文件名编码 uni.downloadFile({ url: url, success: function(res) { var filePath = res.tempFi ...

  10. Java Swing 如何设置图片大小

    如下两行代码搞定: Image image = new ImageIcon("Img/ackground.jpg").getImage();// 这是背景图片 .png .jpg ...