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

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

off999 2024-10-19 07:14 19 浏览 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控制结构,更多实操示例请参照视频讲解。跟着张员外讲编程,学习更轻松,不花钱还能学习真本领。

相关推荐

大文件传不动?WinRAR/7-Zip 入门到高手,这 5 个技巧让你效率翻倍

“这200张照片怎么传给女儿?微信发不了,邮箱附件又超限……”62岁的张阿姨对着电脑犯愁时,儿子只用了3分钟就把照片压缩成一个文件,还教她:“以后用压缩软件,比打包行李还方便!”职场人更懂这...

电脑解压缩软件推荐——7-Zip:免费、高效、简洁的文件管理神器

在日常工作中,我们经常需要处理压缩文件。无论是下载软件包、接收文件,还是存储大量数据,压缩和解压缩文件都成为了我们日常操作的一部分。而说到压缩解压软件,7-Zip绝对是一个不可忽视的名字。今天,我就来...

设置了加密密码zip文件要如何打开?这几个方法可以试试~

Zip是一种常见的压缩格式文件,文件还可以设置密码保护。那设置了密码的Zip文件要如何打开呢?不清楚的小伙伴一起来看看吧。当我们知道密码想要打开带密码的Zip文件,我们需要用到适用于Zip格式的解压缩...

大文件想要传输成功,怎么把ZIP文件分卷压缩

不知道各位小伙伴有没有这样的烦恼,发送很大很大的压缩包会受到限制,为此,想要在压缩过程中将文件拆分为几个压缩包并且同时为所有压缩包设置加密应该如何设置?方法一:使用7-Zip免费且强大的文件管理工具7...

高效处理 RAR 分卷压缩包:合并解压操作全攻略

在文件传输和存储过程中,当遇到大文件时,我们常常会使用分卷压缩的方式将其拆分成多个较小的压缩包,方便存储和传输。RAR作为一种常见的压缩格式,分卷压缩包的使用频率也很高。但很多人在拿到RAR分卷...

2个方法教你如何删除ZIP压缩包密码

zip压缩包设置了加密密码,每次解压文件都需要输入密码才能够顺利解压出文件,当压缩包文件不再需要加密的时候,大家肯定想删除压缩包密码,或是忘记了压缩包密码,想要通过删除操作将压缩包密码删除,就能够顺利...

速转!漏洞预警丨压缩软件Winrar目录穿越漏洞

WinRAR是一款功能强大的压缩包管理器,它是档案工具RAR在Windows环境下的图形界面。该软件可用于备份数据,缩减电子邮件附件的大小,解压缩从Internet上下载的RAR、ZIP及其它类...

文件解压方法和工具分享_文件解压工具下载

压缩文件减少文件大小,降低文件失效的概率,总得来说好处很多。所以很多文件我们下载下来都是压缩软件,很多小伙伴不知道怎么解压,或者不知道什么工具更好,所以今天做了文件解压方法和工具的分享给大家。一、解压...

[python]《Python编程快速上手:让繁琐工作自动化》学习笔记3

1.组织文件笔记(第9章)(代码下载)1.1文件与文件路径通过importshutil调用shutil模块操作目录,shutil模块能够在Python程序中实现文件复制、移动、改名和删除;同时...

Python内置tarfile模块:读写 tar 归档文件详解

一、学习目标1.1学习目标掌握Python内置模块tarfile的核心功能,包括:理解tar归档文件的原理与常见压缩格式(gzip/bz2/lzma)掌握tar文件的读写操作(创建、解压、查看、过滤...

使用python展开tar包_python拓展

类Unix的系统,打包文件经常使用的就是tar包,结合zip工具,可以方便的打包并解压。在python的标准库里面有tarfile库,可以方便实现生成了展开tar包。使用这个库最大的好处,可能就在于不...

银狐钓鱼再升级:白文件脚本化实现GO语言后门持久驻留

近期,火绒威胁情报中心监测到一批相对更为活跃的“银狐”系列变种木马。火绒安全工程师第一时间获取样本并进行分析。分析发现,该样本通过阿里云存储桶下发恶意文件,采用AppDomainManager进行白利...

ZIP文件怎么打开?2个简单方法教你轻松搞定!

在日常工作和生活中,我们经常会遇到各种压缩文件,其中最常见的格式之一就是ZIP。ZIP文件通过压缩数据来减少文件大小,方便我们进行存储和传输。然而,对于初学者来说,如何打开ZIP文件可能会成为一个小小...

Ubuntu—解压多个zip压缩文件.zip .z01 .z02

方法将所有zip文件放在同一目录中:zip_file.z01,zip_file.z02,zip_file.z03,...,zip_file.zip。在Zip3.0版本及以上,使用下列命令:将所有zi...

如何使用7-Zip对文件进行加密压缩

7-Zip是一款开源的文件归档工具,支持多种压缩格式,并提供了对压缩文件进行加密的功能。使用7-Zip可以轻松创建和解压.7z、.zip等格式的压缩文件,并且可以通过设置密码来保护压缩包中的...

取消回复欢迎 发表评论: