百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

后端编程Python3-控制结构(python中控制结构)

off999 2024-10-19 07:14 16 浏览 0 评论

本节是第五讲的第九小节,上节为大家介绍了Python语言组合数据类型的迭代与复制,本节将为大家介绍Python语言的控制结构。

控制结构(Control Structures)

Python通过if语句实现了条件分支,通过while语句与for...in语句实现了循环。Python中还有一种条件表达式是一种if语句,也是Python对C风格语言中使用的三元算子(?:)相对应的内容。

条件分支(Conditional Branching)

下面给出的是Python条件分支语句的最通常的语法:

if boolean_expression1:

suite1

elif boolean_expression2:

suite2

elif boolean_expressionN:

suiteN

else:

else_suite

可以有0个或多个elif语句,最后一个elif语句是可选的。如果我们需要考虑某个特定情况,但在该情况出现时又不需要做什么,那么可以使用pass (充当“什么也不做"占位符)作为该分支的suite。

有些情况下,可以将一条if...else语句缩减为单一的条件表达式,条件表达式的语法是:

expression1 if boolean_expression else expression2 #如果boolean_expression为True,条件表达式的结果为expression1,否则为expression2。

通常的程序设计模式是将某变量设置为默认值,在必要的时候再改变该值,比如, 由于用户的请求进行改变,或者针对程序当前运行平台进行改变。下面给出的是使用 if语句的常规模式:

offset = 20

if not sys.platform.startswith("win"):

offset = 10

sys.platform变量存放的是当前平台的名称,比如,“Win32”或“linux2”。使用条件表达式,可以通过一行代码完成上面的功能:

offset = 20 if sys.platform.startswith("win") else 10

这里并不需要使用圆括号,但是使用圆括号可以避免微妙的陷阱,比如,假定我们想将width变量设置为100,并在margin为True时额外加10,我们可能会使用如下的代码:

width = 100 + 10 if margin else 0 # WRONG!

特别讨厌的地方在于,如果margin为True,上面的代码可以正确工作,并将width 设置为110;如果margin为False,就会错误地将width设置为0,而非100,这是因为,Python将100 + 10看做条件表达式的expression1部分,解决这一问题的方法是使用圆括号:

width = 100 + (10 if margin else 0)

圆括号还可以使得代码更清晰,更适合阅读。

条件分支可用于提高为用户打印的消息,比如,在报告处理的文件数量时,不再打印“0 file(s)”、“1 file(s)”,而是使用一对条件表达式:

print("{0} file{1}".format((count if count != 0 else "no"),("s” if count != 1 else "")))

上面的语句将打印“no files”、“1 file”、“2 files",并且同时会留下一个更专业的印象。

循环(Looping)

Python提供了 while循环与for ... in循环,这两种循环方式实际上都具有比第1章中所展示的基本语法更复杂的语法格式。

while 循环(while Loops)

下面给出的是while循环完整的、通常的语法格式:

while boolean_expression:

while_suite

else:

else_suite

else分支是可选的。只要boolean_expression为True, while块的suite就会执行。 如果boolean_expression为False或变为False,循环就会终止,此时,如果存在可选的else分支,就会执行其suite。在while块的suite内部,如果执行了continue语句, 就会跳转到循环起始处,并对boolean_expression的取值进行重新评估。如果循环不能正常终止,就会跳过所有可选的else分支。

可选的else分支这种叫法很容易让人困惑,因为只要循环是正常终止的,else分支的suite就总会执行。如果由于break语句、或由于返回语句(如果循环在函数或方法内)、或由于发生异常导致跳出循环,else分支的suite就不会执行。(发生异常时, Python会跳过else分支并寻找适当的异常处理部分。)另一方面,else分支的这些特点对while循环、for ...in循环以及try ... except块都是一样的。

让我们看一下else分支的实际使用。str.index()与list.index()方法可以返回给定字符串或数据项的索引位置,并在找不到时产生ValueError异常。str.find()方法完成同样的功能,但在找不到时不会产生异常,而是返回索引值-1,对于列表,没有等价的方法,但如果需要一个完成这一功能的函数,可以使用while循环创建:

def list_find(lst, target):

index = 0

while index < len(lst):

if lst[index] == target:

break

index += 1

else:

index = -1

return index

这一函数在给定的列表中搜索目标。如果找到了目标,就使用break语句终止循环,并返回适当的索引位置。如果找不到目标,就会循环完毕并正常终止,之后执行else的suite:将索引位置设置为-1,并返回该值。

for循环(for Loops)

与while循环类似,for... in循环的完整语法也包括else分支:

for expression in iterable:

for_suite

else:

else_suite

通常,expression或者是一个单独的变量,或者是一个变量序列,一般是以元组形式给出的。如果将元组或列表用于expression,则其中的每一数据项都会拆分到表达式的项。

如果在for... in循环suite中执行了continue语句,那么控制流立即跳转到循环起始处,并开始下一次迭代。如果循环正常执行完毕,就会终止循环,之后执行else suite。如果循环被跳出(由于执行了break语句或return语句),控制流会立即跳转到循环后的语句——所有可选的else suite将被跳过。同样地,如果发生异常,Python会跳过else 分支并寻找适当的异常处理程序。

下面给出了list_find()的for ... in循环实现版本,与while循环实现的版本类似, 这一版本也展示了 else分支的实际应用:

def list_find(lst, target):

for index, x in enumerate(lst):

if x == target:

break

else:

index = -1

return index

如上面代码段所示,在for ... in循环的表达式中创建的变量在循环终止后仍然存在。与所有局部变量类似,他们也将在其闭合范围结尾处终止存在。

异常处理(Exception Handling)

Python通过产生异常来指明发生错误或异常条件——尽管有些第三方Python库使用更过时的技术,比如“error”返回值。

捕获与产生异常(Catching and Raising Exceptions)

异常的捕获是使用try ...except 块实现的,其通常语法如下:

try:

try_suite

except exception_group1 as variable1:

except_suite1

......

except exception_groupN as variableN:

except_suiteN

else:

else_suite

finally:

finally_suite

其中至少要包含一个except块,但else与finally块都是可选的。在try块的suite 正常执行完毕时,会执行else块的suite—如果发生异常,就不会执行。如果存在一 个finally块,则最后总会执行。

每个except分支的异常组可以是一个单独的异常,也可以是包含在括号中的异常元组。对每个异常组,as variable部分是可选的。如果使用,该变量就会包含发生的异常,并可以在异常块的suite中进行存取。

如果某个异常发生在try块的suite中,那么每个except分支会顺序尝试执行。如果该异常与某个异常组匹配,则相应的suite得以执行。要与异常组进行匹配,异常必须与组中列出的异常类型(或其中的某一个)一致,或者与组中列出的异常类型(或其中的某一个)的子类一致。

比如,如果在字典查询中产生KeyError异常,那么包含Exception类的第一个 except分支将匹配这一异常,因为KeyError是Exception的(非直接的)子类。如果没有哪个组列出了 Exception (通常是这种情况),但是存在一个LookupError,那么 KeyError异常也可以匹配,因为KeyError是LookupError的子类。如果没有哪个组列 出了 Exception或LookupError,但是某个组列出了 KeyError,就将匹配该组。

下图展示了从异常体系中抽取的部分关系图:

#下面给出的是不正确使用的一个实例:

try:

x = d[5]

except LookupError: # WRONG ORDER

print("Lookup error occurred")

except KeyError:

print("lnvalid key used")

如果字典d不包含key为5的数据项,那么我们希望产生最具针对性的异常 KeyError,而不是最通常的异常LookupError,但是这里,KeyError except块代码总是无法执行到。如果产生KeyError异常,就会与LookupError except块匹配,因为 LookupError是KeyError的一个基类,也就是说,在异常体系中,LookupError要高于 KeyError,因此,在使用多个except块时,我们必须坚持对其排序,从最具针对性的 (在异常体系中最底层)异常到最通常(异常体系中最顶层)的异常。

try:

x = d[k / n]

except Exception: # BAD PRACTICE

print("Something happened")

要注意的是,上面这种使用except Exception的方法通常并不是一种好做法,因为这种做法将捕捉所有异常,从而很容易掩盖代码中的逻辑错误。在上面的实例中,程序的本意是捕捉KeyErrors,但是如果n为0,就会无意间并且寂静地捕获一个 ZeroDivisionError 异常。

直接写成except:也是可能的,也就是说,不设置异常组。写成这种风格的异常块将捕获任意异常,包括那些继承自BaseException而非Exception的异常,这种做法会导致与使用except Exception同样的问题,甚至更严重,通常情况下应该总是避免这种做法。

如果没有哪个except块匹配该异常,Python会沿着调用栈回溯,并寻找适当的异常处理程序。如果找不到合适的异常处理程序,程序将终止,并在控制台上打印该异常以及回溯信息。

如果没有异常产生,那么任意可选的else块都将执行。在所有情况下——也就是说,如果没有发生异常,或发生异常并被处理,或发生异常并回溯到调用栈——任意 finally块的suite总是会得以执行。如果没有异常产生,或产生的异常被某个except 块处理,那么finally块的suite将在最后执行;如果异常产生,但是没有匹配的except 块,就首先执行finally块的suite,之后将该异常在调用栈中回溯。在需要确保资源被正确释放时,这种执行机制是很有用的。下图勾勒了通常的try ... except... finally语句块控制流。

#下面给出list_find()函数的最终版本,使用了异常处理:

def list_find(lst, target):

try:

index = Ist.index(target)

except ValueError:

index = -1

return index

上面的代码中,有效地使用了 try... except块,将异常转换为错误值。也可以使用同样的方法捕捉某种异常并产生另一种异常——稍后将讨论这一技术。

Python还提供了更简单的try ... finally块,有时也是有用的:

try:

try_suite

finally:

finally_suite

不管try块的suite中发生什么(当然,计算机或程序崩溃除外),finally块的suite 都将得以执行。将with语句与上下文管理器一起使用,也可以达到try ... finally块的效果。

try ... except... finally块的一种常见应用是处理文件错误。比如,noblanks.py程序 从命令行读取一个文件名列表,对其中每个文件,生成一个同名文件,但是后缀名改为.nb,内容上则去除原有文件中的空白行。下面给出的是该程序的read_data()函数:

def read_data(filename):

lines =[]

fh = None

try:

fh = open(filename, encoding="utf8")

for line in fh:

if line.strip():

lines.append(line)

except (lOError, OSError) as err:

print(err)

return []

finally:

if fh is not None:

fh.close()

return lines

上面的代码中,我们将文件对象fh设置为None,因为open。调用可能失败,这种情况下不会为fh赋值(因而fh保持为None),并产生一个异常。如果产生我们指定的某个异常(lOError或OSError),在打印错误消息后,就会返回一个空列表。需要注意的是,在返回之前,finally块的suite将得以执行,因此文件将安全地关闭—— 如果此前该文件被成功打开。

还要注意的是,如果发生编码错误,即便我们并不捕捉相关的异常(ValueError), 文件仍然会安全地关闭。这种情况下,finally块的suite将得以执行,之后异常被向上传递到调用栈——此时没有返回值,因为函数是由于未处理的异常导致结束的。此外, 由于没有适当的except块捕捉编码错误异常,因此程序将终止并打印回溯信息。

我们可以将except分支写的稍详细一些:

except EnvironmentError as err:

print(err)

return []

上面的代码可以正常工作,因为EnvironmentError是lOError与OSError的基类。 在后面,我们将展示一个稍紧凑一些的惯用法,以确保文件被安全关闭,而不需要finally块。

产生异常(Raising Exceptions)

异常提供了一种改变控制流的有用方法。我们可以使用内置的异常,或创建自己的异常,以便产生我们所需要的异常并对其进行处理。有两种可以产生异常的语法:

raise exception(args)

raise exception(args) from original_exception

raise

使用第一种语法时,指定的异常应该或者是内置的异常,或者继承自Exception 的自定义异常。如果给定一些文本作为该异常的参数,那么在捕捉到该异常并打印时, 这些文本应该为输出信息。使用第二种语法,也就是没有指定异常时,raise将重新产生当前活跃的异常——如果当前没有,就会产生一个TypeError。

自定义异常(Custom Exceptions)

自定义异常是自定义的数据类型(类)。创建类在后面讲述,不过创建简单的自定义异常类型比较简单,这里我们展示其基本的语法:

class exceptionName(baseException): pass #基类应该为Exception类或继承自Exception的类。

found = False

for row, record in enumerate(table):

for column, field in enumerate(record):

for index, item in enumerate(field):

if item == target:

found = True

break

if found:

break

if found:

break

if found:

print("found at ({0}, {1}, {2})".format(row, column, index))

else:

print("not found")

上面这15行代码是复杂的,因为我们必须分别跳出每个循环。一种替代的解决方法是使用自定义异常:

class FoundException(Exception): pass

try:

for row, record in enumerate(table):

for column, field in enumerate(record):

for index, item in enumerate(field):

if item == target:

raise FoundException()

except FoundException:

print("found at ({0}, {1}, {2})".format(row, column, index))

else:

print("not found")

这种方法可以将代码削减到10行,或者11行(包含异常定义本身),并且更易于理解。如果发现了要寻找的数据项,就产生自定义的异常,并执行except块的suite, else块则被跳过。如果没有找到相应的数据项,就不会产生异常,并在最后执行else suite。

以上内容部分摘自视频课程05后端编程Python-9控制结构,更多实操示例请参照视频讲解。跟着张员外讲编程,学习更轻松,不花钱还能学习真本领。

相关推荐

推荐一款Python的GUI可视化工具(python 可视化工具)

在Python基础语法学习完成后,进一步开发应用界面时,就需要涉及到GUI了,GUI全称是图形用户界面(GraphicalUserInterface,又称图形用户接口),采用图形方式显示的计算机操...

教你用Python绘制谷歌浏览器的3种图标

前两天在浏览matplotlib官方网站时,笔者无意中看到一个挺有意思的图片,就是用matplotlib制作的火狐浏览器的logo,也就是下面这个东东(网页地址是https://matplotlib....

小白学Python笔记:第二章 Python安装

Windows操作系统的python安装:Python提供Windows、Linux/UNIX、macOS及其他操作系统的安装包版本,结合自己的使用情况,此处仅记录windows操作系统的python...

Python程序开发之简单小程序实例(9)利用Canvas绘制图形和文字

Python程序开发之简单小程序实例(9)利用Canvas绘制图形和文字一、项目功能利用Tkinter组件中的Canvas绘制图形和文字。二、项目分析要在窗体中绘制图形和文字,需先导入Tkinter组...

一文吃透Python虚拟环境(python虚拟环境安装和配置)

摘要在Python开发中,虚拟环境是一种重要的工具,用于隔离不同项目的依赖关系和环境配置。本文将基于windows平台介绍四种常用的Python虚拟环境创建工具:venv、virtualenv、pip...

小白也可以玩的Python爬虫库,收藏一下

最近,微软开源了一个项目叫「playwright-python」,作为一个兴起项目,出现后受到了大家热烈的欢迎,那它到底是什么样的存在呢?今天为你介绍一下这个传说中的小白神器。Playwright是...

python环境安装+配置教程(python安装后怎么配置环境变量)

安装python双击以下软件:弹出一下窗口需选择一些特定的选项默认选项不需要更改,点击next勾选以上选项,点击install进度条安装完毕即可。到以下界面,证明安装成功。接下来安装库文件返回电脑桌面...

colorama,一个超好用的 Python 库!

大家好,今天为大家分享一个超好用的Python库-colorama。Github地址:https://github.com/tartley/coloramaPythoncolorama库是一...

python制作仪表盘图(python绘制仪表盘)

今天教大家用pyecharts画仪表盘仪表盘(Gauge)是一种拟物化的图表,刻度表示度量,指针表示维度,指针角度表示数值。仪表盘图表就像汽车的速度表一样,有一个圆形的表盘及相应的刻度,有一个指针...

总结90条写Python程序的建议(python写作)

  1.首先  建议1、理解Pythonic概念—-详见Python中的《Python之禅》  建议2、编写Pythonic代码  (1)避免不规范代码,比如只用大小写区分变量、使用容易...

[oeasy]python0137_相加运算_python之禅_import_this_显式转化

变量类型相加运算回忆上次内容上次讲了是从键盘输入变量input函数可以有提示字符串需要有具体的变量接收输入的字符串输入单个变量没有问题但是输入两个变量之后一相加就非常离谱添加图片注释,不超过1...

Python入门学习记录之一:变量(python中变量的规则)

写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...

掌握Python的&quot;魔法&quot;:特殊方法与属性完全指南

在Python的世界里,以双下划线开头和结尾的"魔法成员"(如__init__、__str__)是面向对象编程的核心。它们赋予开发者定制类行为的超能力,让自定义对象像内置类型一样优雅工...

11个Python技巧 不Pythonic 实用大于纯粹

虽然Python有一套强大的设计哲学(体现在“Python之禅”中),但总有一些情况需要我们“打破规则”来解决特定问题。这触及了Python哲学中一个非常核心的理念:“实用主义胜于纯粹主义”...

Python 从入门到精通 第三课 诗意的Python之禅

导言:Python之禅,英文名是TheZenOfPython。最早由TimPeters在Python邮件列表中发表,它包含了影响Python编程语言设计的20条软件编写原则。它作为复活节彩蛋...

取消回复欢迎 发表评论: