14-面向对象3

__new__方法

__new__和__init__方法的作用

11 class A(object):                 
 12     def __init__(self):          
 13         print("这是__init__方法")
 14                                  
 15     def __new__(cls):            
 16         print('这是__new__方法') 
 17         return object.__new__(cls)                                                                                                                                        
 18                                  
 19 A()

运行结果如下:

这是__new__方法
这是__init__方法

总结:

  • __new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由python解释器自动提供
  • __new__方法必须要有返回值,返回实例化出来的实例,这点在自己实现__new__要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
  • __init__有一个参数self,就是这个__new__方法返回的实例,__init__方法在__new__的基础上可以完成一些其他初始化的动作,__init__不需要返回值
  • 我们可以将类比作制造商,__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节

异常

异常介绍

当python检测到一个错误的时候,解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的“异常”

举例说明:

print ('------test1-------')
open('123.txt','r')       
print ('------test2-------')

运行结果如下:

------test1-------
Traceback (most recent call last):
  File "05-异常.py", line 12, in <module>
    open('123.txt','r')
FileNotFoundError: [Errno 2] No such file or directory: '123.txt'

说明:打开一个不存在的文件123.txt,当找不到123.txt文件时,就会抛出给我们一个FileNotFoundError类型的错误No such file or directory: '123.txt'(没有123.txt这样的文件或目录)

捕获异常try...except...

看一下示例:

11 try: 
 12     print('-------test1---------')                                                       
 13     open('123.txt','r')
 14     print('-------test2---------')
 15 except FileNotFoundError:
 16     print('文件没有找到')

运行结果如下:

-------test1---------
文件没有找到

说明:

  • 此程序在运行过程中抛出FileNotFoundError类型的错误,我们用了except添加了处理方法

总结:

把可能出现问题的代码放到try中

把处理异常的代码放到exvept中

except捕获多个异常

看如下示例:

11 try:          
 12     print(num)                                                                           
 13 except FileNotFoundError:
 14     print('产生错误')

运行结果如下:

Traceback (most recent call last):
  File "07-捕获多个异常.py", line 12, in <module>
    print(num)
NameError: name 'num' is not defined

我们都已经用except来捕获异常了,那么为什么还会产生错误呢?

因为except捕获的是FileNotFoundError异常信息,没有NameError,所以程序才会出错

修改后的代码如下:

11 try:            
 12     print(num)  
 13 except NameError:                                                                        
 14     print('产生错误')

运行结果如下:

产生错误

在实际开发过程中,捕获多个异常是这样的:

11 try:             
 12     print('-------test1---------') 
 13     open('123.txt','r')
 14     print('-------test2---------') 
 15     print(num)   
 16 except (FileNotFoundError,NameError):
 17     print(errorMsg)

运行结果为:

-------test1---------
Traceback (most recent call last):
  File "06-捕获异常.py", line 13, in <module>
    open('123.txt','r')
FileNotFoundError: [Errno 2] No such file or directory: '123.txt'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "06-捕获异常.py", line 21, in <module>
    print(errorMsg)
NameError: name 'errorMsg' is not defined

注意:

  • 当捕获多个异常的时候,可以把要捕获的异常的名字,放到except后面,并使用元组的方式进行存储

获取异常的信息描述

In [1]: try:
   ...:     print(num)
   ...: except NameError as result:    #as result存储异常的基本信息
   ...:     print(result)
   ...:     
name 'num' is not defined

捕获所有异常

没有存储异常的基本信息

In [1]: try:
   ...:     open('a.txt')
   ...: except:
   ...:     print('产生了一个异常')
   ...:     
产生了一个异常

捕获所有异常,并且存储异常的基本信息

In [2]: try:
   ...:     open('a.txt')
   ...: except Exception as result:
   ...:     print('捕获到了异常')
   ...:     print(result)
   ...:     
捕获到了异常
[Errno 2] No such file or directory: 'a.txt'

else

我们对else应该不陌生,在if中,它的作用是当条件不满足时执行的实行,同样在try...except中也是如此,即如果没有捕获到异常,那么就需要执行else的事情

In [4]: try:
   ...:     num = 100
   ...:     print(num)
   ...: except NameError as result:
   ...:     print('捕获到了异常')
   ...:     print(result)
   ...: else:
   ...:     print('没有捕获到异常,真开心')
   ...:     
100
没有捕获到异常,真开心

try...finally...

在程序中,如果一个段代码必须要执行,即无论异常是否产生都要执行,那么此时就需要使用finally。比如关闭文件,释放锁,把数据库连接返回给连接池等

举例说明:

1 #!/usr/bin/python                                                                                   
  2 #coding=utf8
  3 """
  4 # Author: xiaoyafei
  5 # Created Time : 2018-04-08 18:46:34
  6  
  7 # File Name: 08-try_finally.py
  8 # Description:
  9  
 10 """
 11 import time
 12 try:
 13     f = open('test.txt')
 14     try:
 15         while True:
 16             content = f.readline()
 17             if len(content)==0:
 18                 break
 19             time.sleep(2)
 20             print(content)
 21     except:
 22         #如果在读取文件的过程中产生了异常,那么就会捕捉到
 23         #比如,按下了ctrr+c
 24         pass
 25     finally:
 26         f.close()
 27         print('文件已正常关闭')
 28 except:
 29     print('没有这个文件')

然后, 需要在当前目录下touch文件test.txt,然后再运行,运行结果如下:

文件已正常关闭

说明:

  • test.txt文件中每一行数据打印,但是可以在每次打印的时候暂停2秒,这样的做法就是让程序运行慢一点,在程序运行的时候,可以ctrl+c中断程序
  • 当按下ctrl+c的时候,异常被触发,程序退出,但是在退出程序之间,finally从句依然被执行把文件关闭

异常的嵌套

try嵌套

1 #!/usr/bin/python
  2 #coding=utf8
  3 """  
  4 # Author: xiaoyafei
  5 # Created Time : 2018-04-08 18:46:34
  6      
  7 # File Name: 08-try_finally.py
  8 # Description:
  9      
 10 """  
 11 import time
 12 try: 
 13     f = open('test.txt')
 14     try:
 15         while True:
 16             content = f.readline()
 17             if len(content)==0:
 18                 break
 19             time.sleep(2)
 20             print(content)
 21     except:
 22         #如果在读取文件的过程中产生了异常,那么就会捕捉到
 23         #比如,按下了ctrr+c
 24         pass
 25     finally:                                                                                                       
 26         f.close()
 27         print('文件已正常关闭')
 28 except:
 29     print('没有这个文件')

需要在当前目录下touch test.txt,然后在里面随便写点东西,运行结果如下:

aaaaaaaaaaaaaaaaaaaa

^C文件已正常关闭    #ctrl+c

函数嵌套调用中

1 #!/usr/bin/python
  2 #coding=utf8
  3 """      
  4 # Author: xiaoyafei
  5 # Created Time : 2018-04-08 19:01:45
  6          
  7 # File Name: 09-异常的传递-函数调用中.py
  8 # Description:
  9          
 10 """      
 11 def test1():
 12     print('----------test1-1---------')
 13     print(num)
 14     print('----------test1-2---------')
 15          
 16 def test2():
 17     print('----------test2-1---------')
 18     test1()
 19     print('----------test2-2---------')
 20          
 21 def test3():
 22     try: 
 23         print('----------test3-1---------')
 24         test1()
 25         print('----------test3-2---------')                                                                        
 26     except Exception as result:
 27         print('捕获到了异常,信息是:%s'%result)
 28          
 29     print('----------test3-2---------')
 30          
 31 test3()  
 32 print('------------------华丽的分割线---------------')
 33 test2()

运行结果如下:

----------test3-1---------
----------test1-1---------
捕获到了异常,信息是:name 'num' is not defined
----------test3-2---------
------------------华丽的分割线---------------
----------test2-1---------
----------test1-1---------
Traceback (most recent call last):
  File "09-异常的传递-函数调用中.py", line 33, in <module>
    test2()
  File "09-异常的传递-函数调用中.py", line 18, in test2
    test1()
  File "09-异常的传递-函数调用中.py", line 13, in test1
    print(num)
NameError: name 'num' is not defined

当调用test3函数时,在test1的函数内部产生了异常,此异常会被传递到test3函数中完成了异常处理,而当异常处理完后,并没有返回到函数test1中进行执行,而是在函数test3中继续执行

总结:

  • 如果try嵌套,那么如果里面的try没有捕获到这个异常,那么外面的try会接收到这个异常,然后进行处理,如果外边的try依然没有捕获到,那么再进行传递...
  • 如果一个异常实在一个函数中产生的,例如函数A-->函数B-->函数C-->,而异常是在函数 C中产生的,那么如果函数C中没有对这个异常进行处理,那么这个异常就会传递给B,如果函数B有异常处理那么则会按照函数B的处理方式进行执行;如果函数B也没有异常处理,那么这个异常会继续传递,以此类推......

抛出自定义的异常

可以用raise语句来引发一个异常。异常/错误对象必须要有一个名字,且他们应该是Error或Exception类的子类

下面是一个引发异常的例子:

1 #!/usr/bin/python         
  2 #coding=utf8              
  3 """                       
  4 # Author: xiaoyafei       
  5 # Created Time : 2018-04-08 19:14:00
  6                           
  7 # File Name: 10-抛出自定义的异常.py
  8 # Description:            
  9                           
 10 """                       
 11 class ShortInputError(Exception):
 12     '''自定义的异常类'''  
 13     def __init__(self,length,alteast):
 14         super().__init__()                                                                                         
 15         self.length = length
 16         self.alteast = alteast
 17                           
 18 def main():               
 19     try:                  
 20         s = input('请输入----->')
 21         if len(s)<3:      
 22             #raise引发一个自定义的异常
 23             raise ShortInputError(len(s),3)
 24     except ShortInputError as result:
 25         print('ShortInputError:输入的长度是%d,长度至少是%d'%(result.length,result.alteast))
 26     else:                 
 27         print('没有异常') 
 28 main()

运行结果如下:

python@ubuntu:~/codes/python基础-09$ python3 10-抛出自定义的异常.py 
请输入----->
ShortInputError:输入的长度是0,长度至少是3
python@ubuntu:~/codes/python基础-09$ python3 10-抛出自定义的异常.py 
请输入----->a
ShortInputError:输入的长度是1,长度至少是3
python@ubuntu:~/codes/python基础-09$ python3 10-抛出自定义的异常.py 
请输入----->bd 
ShortInputError:输入的长度是2,长度至少是3
python@ubuntu:~/codes/python基础-09$ python3 10-抛出自定义的异常.py 
请输入----->dad
没有异常

在以上代码中,关于suprt().__init__()的说明:

这一行代码,可以调用也可以不调用,建议调用,因为__init__方法 往往是用来创建完对象进行初始化工作,如果在子类中重写了父类的__init__方法,即意味着父类中的很多初始化工作没有做,这样就不能保证程序的稳定了,所以在以后的开发过程中,如果重写了父类的__init__方法,最好是先调用父类的这个方法,然后再添加自己的功能

异常处理中抛出异常

#!/usr/bin/python
#coding=utf8
"""
# Author: xiaoyafei
# Created Time : 2018-04-08 19:25:59
 
# File Name: 11-异常处理中抛出异常.py
# Description:
 
"""
class Test(object):
    def __init__(self,switch):
        self.switch = switch    #开关
    def cacl(self,a,b):
        try:
            return a/b
        except Exception as result:
            if self.switch:
 
                print('捕获开启,已经捕获到了异常,信息如下:')
                print(result)
            else:
                #重新抛出这个异常,此时就不会被这个异常给捕获到,从而触发默认的异常处理
                raise
a = Test(True)
a.cacl(11,0)
print('--------------------------华丽的分割线--------------------------')
a.switch = False
a.cacl(11,0)

运行结果如下:

捕获开启,已经捕获到了异常,信息如下:
division by zero
--------------------------华丽的分割线--------------------------
Traceback (most recent call last):
  File "11-异常处理中抛出异常.py", line 29, in <module>
    a.cacl(11,0)
  File "11-异常处理中抛出异常.py", line 16, in cacl
    return a/b
ZeroDivisionError: division by zero