关于python:Python6决策循环与异常处理

引言

这篇文章介绍python中的流程管制与异样解决。

文章目录

0×1.应用if做出决策
0×2.循环
0×3.迭代器
0×4.异样捕捉与解决

0×1.应用if做出决策

python的if语句与其余编程语言最大的区别解释每个分支前面都须要增加一个阐明号,请看上面的实例:

#!/usr/bin/env python3
#coding=utf-8
try:
    a=input("请输出整数0:")
    if int(a)==0:
        print("www.qingsword.com")
    elif int(a)>0:
        print("a大于0")
    else:
        print("a小于0")
except ValueError as err:
    print(err)

#这是一个简略的小程序,try...except语句用于捕捉代码运行时的异样,也就是说,如果try中蕴含的语句执行出错,会跳转到except分支去匹配异样类型,本例仅提供了一种谬误类型,即ValueError异样,当用户输出了一个非数字的时候,int(a)转换函数会抛出这个异样,这个异样会被print(err)语句打印在屏幕上,err是自定义的变量名,相当于ValueError异样信息的一个援用

#input()函数会挂起程序,期待用户的输出,依据用户的输出执行if判断,如果等于0则打印出本站网址,如果大于0则匹配elif分支,如果小于0则匹配else分支,if语句块中能够蕴含多个elif分支用来匹配不同状况,当所有状况都不匹配时匹配else分支,if语句从上往下顺次执行每个分支,只有其中一个分支匹配胜利,执行完分支下的语句后,立刻跳出if语句块,不再匹配前面的分支(就算前面的分支可能匹配,也不执行)

0×2.循环

python中有两种循环,while和for,请看上面的实例;

while循环实例:

#!/usr/bin/env python3
#coding=utf-8
#导入python自带的随机数生成器
import random

#while后的条件为True就会始终循环
while True:
    #随机生成1到100中的一个数字
    i=random.randint(1,100)
    #如果这个数字小于50,continue语句会让流程跳转到while开始处持续循环
    if i<50:
        continue
    #如果大于等于50,打印出这个数字,break语句会终止并跳出循环
    print(i)
    break

#另一个while循环实例,num会从5递加,直到0时num大于0为假,终止循环
num=5
while num>0:
    print(num)
    num-=1

for循环实例:

#!/usr/bin/env python3
#coding=utf-8

#从元组中顺次读取每个元素打印
for i in ("a","b","c"):
    print(i)

#range()办法承受三个参数,别离为range(起始数字,完结数字,公差),当仅设置一个参时,起始数字默认为0,公差默认为1,本例i将从0读取到4,但不会蕴含4,所以打印出的数字应该是0,1,2,3
for i in range(4):
    print(i)

#设置了起始数字为1,完结数字为4,打印出1,2,3
for i in range(1,4):
    print(i)

#公差为2,打印出0到11之间的所有偶数
for i in range(0,11,2):
    print(i)

#for循环顺次读取列表数据的实例,len()计算出a的长度为3,range(3)相当于(0,1,2)这样的元组列表,print函数打印出列表中每个索引地位所对应的元素
a=["www.qingsword.com","晴刃","qingsword"]
for i in range(len(a)):
    print(str(i)+"~"+a[i])

#除了可能应用下面这种办法打印出每个元素对应的索引外,python还提供了一个enumerate函数,可能间接将列表分解成索引对应元素的模式,例如
#!/usr/bin/env python
#coding=utf-8
L=["a","b","c","d"]
print(tuple(enumerate(L)))
for i,a in enumerate(L):
    print(i,a)

#程序输入
((0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'))
0 a
1 b
2 c
3 d

for迭代字典实例:

#!/usr/bin/env python
#coding=utf-8

d={"one":1,"two":2,"three":3,"four":4}
#默认状况仅遍历字典的key,这等同于"for a in d.keys()"
for a in d:
    print(a)
#如果想要遍历值,能够应用上面的办法
for a in d.values():
    print(a)
#如果同时想遍历键值,能够在in之前应用两个变量
for a,b in d.items():
    print(a,b)

#程序输入
one
two
four
three
1
2
4
3
one 1
two 2
four 4
three 3

#for中携带多个变量不仅能够用在字典中,也能用在多维列表或元组中,例如
#!/usr/bin/env python
#coding=utf-8
L=[[1,11,111],[2,22,222],[3,33,333]]
for x,y,z in L:
    print(x,y,z)

#程序输入
1 11 111
2 22 222
3 33 333

for迭代字符串实例:

#!/usr/bin/env python
#coding=utf-8

s0="www.qingsword.com"
s1=""
for a in s0:
    s1+=a
print(s1)

#程序应用for循环每次读取s0中的一个字符并将它增加到s1中,实现s0到s1的复制

Ps:while循环中的continue和break语句同样实用于for循环。

0×3.迭代器

列表,字典,元组,字符串都是可迭代类型,那么如何判断哪种数据类型可迭代呢?能够应用collections模块的Iterable类型来判断,例如:

#coding=utf-8
from collections import Iterable

print(isinstance(123,Iterable))
print(isinstance("www.qingsword.com",Iterable))
print(isinstance(["www.qingsword.com","qingsword"],Iterable))

#程序输入,从输入能够看到,整型123不能迭代,所以返回False,前面的字符串与列表都是可迭代类型
FALSE
TRUE
TRUE

这些能够间接作用于for循环的对象统称为可迭代对象(Iterable),而生成器(列表生成器和函数生成器)岂但能够作用于for循环,还能够被next()函数一直调用并返回下一个值,直到最初抛出StopIteration谬误。能够被next()函数调用并一直返回下一个值的对象称为迭代器(Iterator);能够应用isinstance()判断一个对象是否是Iterator对象:

#!/usr/bin/env python
#coding=utf-8
from collections import Iterator
print(isinstance([],Iterator))
print(isinstance("www.qingsword.com",Iterator))
print(isinstance({},Iterator))
print(isinstance((x for x in range(3)),Iterator))

#从上面的输入能够看到,列表字符串和字典,尽管都是可迭代对象(Iterable),但他们都不是迭代器(Iterator),只有最初的列表生成器才是迭代器(是列表生成器而不是列表生成式,留神两者括号上的区别,一个是中括号,一个是圆括号,并且两者工作形式不一样)
FALSE
FALSE
FALSE
TRUE

在Python中,迭代器保留了一组算法,这组算法能够计算出一个数据流,这个数据流能够无穷大(比方实数汇合),也能够是无限的数据流,迭代器对象能够被next()函数调用并一直返回下一个数据,直到没有数据时抛出StopIteration谬误,所以迭代器对象是当咱们拜访这个迭代器时才计算出数据流中的下一个值。

python容许应用iter()函数,将一个可迭代对象转换成迭代器,例如:

#!/usr/bin/env python
#coding=utf-8
from collections import Iterator
print(isinstance(iter([]),Iterator))
print(isinstance(iter("www.qingsword.com"),Iterator))

#程序输入
TRUE
TRUE

for循环与迭代器的比拟如下:

#!/usr/bin/env python
#coding=utf-8
L1=[1,2,3]
L2=iter(L1)

#for循环迭代
for a in L1:
    print(a)

#应用next()读取迭代器L2中的值(也能够应用for循环)
while True:
    try:
        print(next(L2))
    except StopIteration as err:
        break

从这个实例能够看出,Python的for循环与调用next()函数拜访迭代器,他们实质上是统一的。

0×4.异样捕捉与解决

对于异样解决的语句在if中曾经简略演示过,try语句块和if一样,能够蕴含多个except分支用于捕捉异样,在try开端还能增加一个else分支,当没有捕捉到异样时将会运行这个分支下的内容,可能有敌人会问:”我怎么会晓得异样名称是什么?什么时候会产生什么异样?”,当咱们应用解释器运行程序的时候,总会遇见一些谬误,产生谬误时解释器会返回一个异样信息,其中就蕴含了异样名称,咱们只须要将这些名称记录下来,而后应用except捕捉他们即可,请看上面的实例:

#!/usr/bin/env python3
#coding=utf-8

d={1:"banana",2:"apple",3:"orange",4:"durian"}
try:
    i=input("输出你须要的水果编号(1-4):")
    i=int(i)
    if i==1:
        print(d[i])
    elif int(i)==2:
        print(d[i])
    elif int(i)==3:
        print(d[i])
    elif int(i)==4:
        print(d[i])
    else:
        print(d[i])
except ValueError as err:
    print(err)
except KeyError as err:
    pass
else:
    print("未捕捉到异样")
finally:
    print("End")

#异样解决语句块能够蕴含多个except用来捕捉不同的异样,当不须要对捕捉到的异样进行解决时,能够在分支中输出pass,代表不做任何操作,try语句块的开端能够追随一个else分支,当没有捕捉到异样时会执行这个分支,但个别不须要增加这个分支,同时还能够增加一个finally分支,不管有没有捕捉到异样,这个分支都会被执行,当程序执行过程中遇到异样时,如果增加了异样解决语句,会间接跳转到异样分支进行解决,而不继续执行上面的语句,如果没有任何异样解决可能匹配,程序会因为出错而间接终止运行

#执行下面的程序,当输出一个非数字的字符时,会触发ValueError异样(这个ValueError就是异样名),并且打印出异样信息(这个异样是在i=int(i)时产生的,因为要被转换的字符不是数字)
输出你须要的水果编号(1-4):a
invalid literal for int() with base 10: 'a'

#当输出一个范畴不在1-4中的数字时,会触发KeyError异样,这个异样是在if块的else分支下的print(d[i])语句中产生的,如果我输出的是6,d[6]在字典中基本找不到对应的键,所以抛出"键谬误",然而这条分支上面应用了pass,这会让程序静默解决,不会在屏幕上产生任何输入

#当程序没有异样时,输入如下
输出你须要的水果编号(1-4):1
banana
未捕捉到异样
End

除了应用try捕捉异样外,还可能应用raise来被动的抛出一个异样,例如:

#!/usr/bin/env python3
#coding=utf-8
#创立一个绝对值转换函数
def my_abs(x):
    """绝对值转换函数,如果传入的不是一个整数或浮点数,则应用raise关键字抛出一个TypeError异样,isinstance()函数接管两个参数,第一个参数是要判断的传入值,第二个参数是一个判断范畴,本例判断x是否为整形和浮点型"""
    if not isinstance(x,(int,float)):
        raise TypeError("Bad operand type.")
    elif x>=0:
        return x
    else:
        return -x

print(my_abs(-123))
print(my_abs(23))
print(my_abs(-3.14))

#程序输入
123
23
3.14

#如果传入一个谬误的值,就会失去一个TypeError
print(my_abs("www.qingsword.com"))
TypeError: Bad operand type.

有时候咱们捕捉到了一种谬误,但却想抛出另外一种类型的谬误(尽管这种状况并不多见),也能够应用raise关键字,例如:

#!/usr/bin/env python3
#coding=utf-8
def A(x=233):
    return x/0 #会遇到一个被除数不能是0的谬误
try:
    A()
except ZeroDivisionError as err:
    #捕捉这个谬误后,自定义抛出一个TypeError谬误
    raise TypeError("个别,不要抛出齐全不同类型的谬误")

下面这种抛出一个齐全不同类型的谬误并不是举荐的做法,除非你晓得本人在做什么,正确的抛出错误方法如下:

#!/usr/bin/env python3
#coding=utf-8
def A(x=233):
    try:
        return x/0
    except ZeroDivisionError as err:
        print("被除数不能是0")
        raise #如果不带参数,就会把以后谬误原样抛出
A()

再来看一个谬误实例,Python容许应用try捕捉谬误,但如果没有应用try语句,那么谬误会从源头开始一层层返回,直到被python解释器捕捉,例如上面的程序:

#!/usr/bin/env python3
#coding=utf-8
def A(x):
    return x/0 #谬误的发祥,0不能是被除数
def B(x):
    return A(x)*2
def C():
    B(0)

#当咱们执行C()的时候,程序就会报错
C()
print("End") #这一句没有被执行,程序出错后就终止了

#谬误输入
File "test2.py", line 10, in <module>
  C() #首先判断出谬误是因为这个语句引起
File "test2.py", line 8, in C
  B(0) #但这个谬误是因为C的B(0)语句
File "test2.py", line 6, in B
  return A(x)*2 #谬误又被追溯到B中的return语句
File "test2.py", line 4, in A
  return x/0 #最初才追溯到A中的return语句
#打印出谬误类型是ZeroDivisionError,被除数不能是0
builtins.ZeroDivisionError: division by zero

咱们留神到下面的程序在除错后就间接终止了,但理论状况中咱们可能须要记录并打印出这些错误信息,但依然让程序持续运行直到完结,能够应用日志记录模块logging来实现这些操作,批改下面的程序如下:

#!/usr/bin/env python3
#coding=utf-8
import logging #引入日志模块
def A(x):
    return x/0
def B(x):
    return A(x)*2
def C():
    try:
        B(0)
    except Exception as err:
        logging.exception(err)  #记录并打印捕捉到的谬误

C()
print("end")

#将logging.exception写在except中可能记录并打印出谬误日志,输入这些谬误日志信息后,程序会继续执行,最初打印出end(日志记录模块比print更加具体的记录了谬误的调用步骤,让咱们可能明确谬误的源头在哪里,如果只是print(err)就只会打印出division by zero),上面是程序输入
ERROR:root:division by zero
Traceback (most recent call last): #谬误跟踪信息
  File "test2.py", line 10, in C
    B(0)
  File "test2.py", line 7, in B
    return A(x)*2
  File "test2.py", line 5, in A
    return x/0
ZeroDivisionError: division by zero
end  #程序报错后继续执行,直到完结

大家可能留神到了咱们捕捉的不同谬误都有谬误名称,这些名称在Python中是分层设计的(谬误其实也是类,所有的谬误类型都继承自BaseException),不同的谬误有它们的父类和子类,父类的捕捉优先级高于子类,也就意味着咱们在except中如果设置了一个父类的名称,那么它将捕捉所有子类谬误,而再写一个except捕捉它的子类就没有意义了,也不永远不会被执行,上面这个列表列出了所有的谬误类,缩进的是子类,通过这个列表不难看出,为什么在下面的实例中通过捕捉Exception谬误就能捕捉到ZeroDivisionError谬误,因为ZeroDivisionError是Exception的子类:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理