乐趣区

关于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
退出移动版