Python 3之流程控制

Python 3之流程控制

if语句

if语句用于条件判断,有几种形式:

  • 仅if语句
  • if语句加else语句
  • if语句,后带一个或多个elif语句,以及可选的else语句
import math
from numbers import Number
def myfunc(x=0):
    if not isinstance(x, Number):
        raise TypeError
    elif x <= 0:
        return 0
    elif x <= 1:
        return x
    else:
        return math.log1p(x)
    
print(myfunc(-10))
print(myfunc(0))
print(myfunc(0.5))
print(myfunc(1))
print(myfunc(100))
0
0
0.5
1
4.61512051684126

if语句的结构并不难理解,但Python中可用于if语句的条件判断的形式比较多,比如上面例子中用到的就有not和比较运算。总结起来,主要有以下一些形式。

  • 比较运算。包括==, !=, >=, <=, >, <。默认情况下,任何两个对象都可以进行和!=判断,因为object类提供了默认实现。但其它比较运算则需要具体类型支持。值得注意的是,object类实现的和!=是基于对象id进行的,也就是说只有两个对象相同,才能判断为相等==。但有些数据类型并非这样,典型例子就是序列类型,相等和相同并不是一回事。
  • 真值测试,形式很简单,就是直接使用对象进行测试,比如’obj’或者’not obj’。几乎所有类型的对象都可以进行真值测试,但不同类型的对象进行测试时的情况并不完全相同。真值测试优先调用对象的__bool__()方法,如不支持则尝试调用__len()__()方法,如都不支持则尝试进行转换,即直接调用bool类型构造器bool(obj)。
  • 标识判断,即’is’表达式,形式为’a is b’或者’a is not b’。用于判断两个对象是否相同(id相同)。
  • 成员检测,即’in’表达式,形式为’x in s’或者’x not in s’。如果x是s的成员,则’x in s’为真值。在判断成员时,优先尝试s的__contains__()方法;如不支持则对s进行迭代查找,即调用s的__iter__()方法得到迭代器,并使用迭代器对s进行迭代查找,如果找到某个z满足’z is x’或者’z==x’,则’in’表达式为True,否则为False;如前面两种方法都不支持,则尝试用__getitem__()方法对索引进行迭代搜索。如果以上三个方法s都不支持,那么不能用in表达式。
  • 赋值表达式,一种采用’:='符号的特殊的赋值形式也可用作条件判断。需要注意的是,这和普通的赋值语句不一样,普通赋值语句不能这么用。此时判断的是赋值后的对象。
  • 数学运算,数学运算的结果也是一个对象,因此这其实和真值测试的情况差不多。根据运算的对象类型不同,运算结果的对象类型也不同,只不过是对运算结果对象做真值测试。同理,位运算表达式也一样。
  • 逻辑运算,逻辑运算其实是先对每个部分求真值,再把各个部分的值进行逻辑运算。而每个部分其实又是前述几种表达式之一或者是一个逻辑运算表达式,因此它只是一个复合结果,每个部分求真值最终都会回归到前面几种情况之一。逻辑运算包括’and’, ‘or’和’not’。当not用于is表达式时,与’is not’效果一样;当not用于in表达式时,与’not in’效果一样;但not还可用于其它情况,前面两个只不过是其特例,而’is not’则只能用于对象判断,'not in’则只能用于成员判断。

详见下面的例子。

from random import randint

o=object()
o2=object()
n0=0
n=100
f0=0.0
f=100.0
nan=float('nan')
s0=''
s='hello'
l=[]

# comparison test
print('\ncomparison test:')
if n0 == s0:
    print('n0==s0: True')
if n0<n<101:
    print('n0<n<101: True')
if o==o2:
    print('o==o2: True')
if s0==str():
    print('s0==str(): True')
if l==list():
    print('l==list(): True')
try:
    if o > o2:
        print('o > o2: True')
except TypeError as e:
    print(e)
if None == False:
    print('None == False: True')
if nan == False:
    print('nan == False: True')
if n0 == False:
    print('n0 == False: True')

# truth test on any obj
print('\ntruth test:')
if o:
    print('o: True')
if n0:
    print('n0: True')
if n:
    print('n: True')
if f0:
    print('f0: True')
if nan:
    print('nan: True')
if s0:
    print('s0: True')
if s:
    print('s: True')
if l:
    print('l: True')
if None:
    print('None: True')

# is test
print('\nis test:')
if n is int(100):
    print('n is 100: True')
if o is o2:
    print('o is o2: True')
if s0 is str():
    print('s0 is str(): True')
if l is list():
    print('l is list(): True')
if None is False:
    print('None is False')

# in test
print('\nin test:')
try:
    if n0 in n:
        print('True')
except TypeError as e:
    print(e)
if 'hel' in s:
    print('"hel" in s: True')
if None in l:
    print('None in l: True')
    
# assignment
print('\nassignment test:')
if not (l2:=(1,2,3)):
    print('l2 is empty')
if res:=randint(-10, 10):
    print('non-zero random number:', res)
    
# math operations test
print('\nmath test:')
if n0+f0:
    print('n0+f0: True')
if n0^n:
    print('n0^n: True')
    
# logical operations test
print('\nlogical test:')
if nan or None:
    print('nan or None: True')
    
if not None is False:
    print('not None is False: True')
if None is not False: 
    print('None is not False: True')
if not n in l:
    print('not n in l: True')
if n not in l:
    print('n not in l: True')
if not None:
    print('not None: True')
comparison test:
n0<n<101: True
s0==str(): True
l==list(): True
'>' not supported between instances of 'object' and 'object'
n0 == False: True

truth test:
o: True
n: True
nan: True
s: True

is test:
n is 100: True
s0 is str(): True

in test:
argument of type 'int' is not iterable
"hel" in s: True

assignment test:
non-zero random number: -5

math test:
n0^n: True

logical test:
nan or None: True
not None is False: True
None is not False: True
not n in l: True
n not in l: True
not None: True

if语句还可用作条件表达式,从而达到类似于C语言中的三元操作符的作用。其形式为’x if C else y’,表示C为True时取值x否则取值y。举例如下。

from random import randint

s='not zero' if randint(0,2) else 'zero'
print(s)

def myvalue(use_random=False):
    return randint(1, 100) if use_random else 0

print(myvalue())
print(myvalue(True))
not zero
0
83

循环

Python中的循环结构有两种形式,while循环和for循环。while循环的形式是’while 条件’,当条件为True时循环继续,否则循环退出,条件判断和前面if语句一样。for循环的则用于枚举可迭代对象(序列、字典、集合等),跟某些编程语言里扩展的for_each类似。因此while循环和for循环的用途并不重叠。见下面的例子。

from random import randint
a, b = 0, 1
while a < 1000:
    print(a, end=',')
    a, b = b, a+b
print('\n')
    
l=[]
for i in range(0, 21):
    l.append(randint(0, 10))

print(l)
0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,

[4, 7, 3, 9, 0, 3, 6, 3, 6, 10, 5, 7, 0, 1, 4, 4, 5, 8, 10, 5, 9]

值得注意的是,in表达式可用于条件判断,因此也可用在while循环中,但这与for循环中的用法及含义并不相同。

def myremove(l,x):
    while x in l:
        l.remove(x)
        
for x in range(0,4):
    myremove(l, x)
print(l)
[4, 7, 9, 6, 6, 10, 5, 7, 4, 4, 5, 8, 10, 5, 9]

与C语言类似,Python的循环也支持break语句和continue语句。break语句用于提前结束循环,continue语句则表示跳过本次循环后面的语句,继续执行循环的下一次迭代。此外,Python的循环还支持else语句,在循环结束时执行。哪怕循环一次也没执行,else也会执行。见下面的例子。

for n in range(2, 10):
    for x in range(2, n):
        if n % x == 0:
            print(n, 'equals', x, '*', n//x)
            break
    else:
        # loop fell through without finding a factor
        print(n, 'is a prime number')
            
for num in range(2, 10):
    if num % 2 == 0:
        print("Found an even number", num)
        continue
    print("Found an odd number", num)
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3
Found an even number 2
Found an odd number 3
Found an even number 4
Found an odd number 5
Found an even number 6
Found an odd number 7
Found an even number 8
Found an odd number 9

pass语句

pass语句的作用相当于’nop’,用于不需要执行任何操作但又需要一条语句的情况。比如定义一个空函数,空类型等。

class MyEmptyClass:
    pass

def myemptyfunc():
    pass

def mydelay(x):
    while x:=x-1:
        pass
    
mydelay(10000)

异常处理

Python在执行一个程序时,如果某一行抛出了一个异常,Python就会搜索异常处理代码。异常处理的基本形式是try子句加上except子句,将可能产生异常的代码放入try子句中,将异常处理代码放入except子句。每个except子句可以处理一种或者多种类型的异常。

def one_div_by(x):
    return 1/x

objs=(0,[],'a',1,2,3,float('inf'))
s=0
r=0
for o in objs:
    try:
        r=one_div_by(o)
    except ZeroDivisionError as e:
        print(e)
        continue
    except TypeError as e:
        print(e)
        continue
    s += r
print(s)
division by zero
unsupported operand type(s) for /: 'int' and 'list'
unsupported operand type(s) for /: 'int' and 'str'
1.8333333333333333

except子句后面还可以跟else子句和finally子句。如果try子句中没有产生异常,则else子句将执行。而finally子句则是无论何种情况,在控制退出try子句前,都会被执行,常用作清理。具体来说有三种情况:

  • try子句保护的代码块没有异常产生,finally会执行。见下面的第一个例子,没有异常产生,else和finally都执行。
  • try子句保护的代码有异常产生,且被跟随的except子句处理,finally会执行。见下面的第二个例子,产生的ZeroDivisionError被处理,else不执行,finally执行。
  • try子句保护的代码有异常产生,且跟随的except子句无法处理。此时,异常会继续抛出,搜索更上一层的异常处理。见下面的第三个例子,内层的异常处理程序只能处理TypeError,而产生的是ZeroDivisionError,因此无法处理,抛出到外层。但在控制从内层的try退出前,内层finally得以执行。外层处理完后,控制要退出外层的try之前,外层finally得以执行。
print('1st example: no exception')
try:
    one_div_by(100)
except Exception as e:
    print(e)
else:
    print('no exception')
finally:
    print('cleanup')

print('\n2nd example:')
try:
    one_div_by(0)
except ZeroDivisionError as e:
    print(e)
else:
    print('no exception')
finally:
    print('cleanup')
    
print('\n3rd example:')
try:
    try:
        one_div_by(0)
    except TypeError as e:
        print('inner exception handler:', e)
    finally:
        print('inner finally')
except Exception as e:
    print('outter exception handler:', e)
finally:
    print('outter finally')
    
1st example: no exception
no exception
cleanup

2nd example:
division by zero
cleanup

3rd example:
inner finally
outter exception handler: division by zero
outter finally

finally子句也可和try子句直接配合使用。这种情况一般是想在抛出异常前进行清理。try子句里可能会产生异常,但是这里不想处理,而是想抛出到外层处理。比如上面的第三个例子也可以写成如下形式。

try:
    try:
        one_div_by(0)
    finally:
        print('inner finally')
except Exception as e:
    print('outter exception handler:', e)
finally:
    print('outter finally')
    
inner finally
outter exception handler: division by zero
outter finally

从前面的例子也可以看出,异常处理是可以嵌套的。一个异常产生时,优先检查最内层的异常处理,如果能处理则处理,否则抛出到上一层,如此继续。如果没有任何异常处理程序能处理,则系统捕获异常并终止程序。

如果想在异常处理中打印调用栈,则可以使用traceback工具。如果想显示地抛出一个异常,则可食用raise语句。

import traceback
try:
    one_div_by(0)
except ZeroDivisionError as e:
    traceback.print_exc()
Traceback (most recent call last):
  File "<ipython-input-18-6331485edc05>", line 3, in <module>
    one_div_by(0)
  File "<ipython-input-8-584aee14c023>", line 2, in one_div_by
    return 1/x
ZeroDivisionError: division by zero
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页