设为首页 收藏本站
查看: 510|回复: 0

[经验分享] [PYTHON] 核心编程笔记之十-Python错误和异常

[复制链接]

尚未签到

发表于 2018-8-4 10:27:24 | 显示全部楼层 |阅读模式
  10.1 什么是异常
  10.1.1 错误
  错误时语法或是逻辑上的,语法错误指示软件的结构上有错误,导致不能被解释器解释或编译器无法编译
  当Python检测到一个错误时,解释器就会支出当前流已经无法继续执行下去,这时就出现了异常
  10.1.2 异常
  10.2 Python中的异常
  例:
  NameError: 尝试访问一个未声明的变量
  >>> foo
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  NameError: name 'foo' is not defined
  除数为零:
  >>> 1/0
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ZeroDivisionError: integer division or modulo by zero
  Python解释器语法错误:
  >>> for
  File "<stdin>", line 1
  for
  ^
  SyntaxError: invalid syntax
  请求的索引超出序列范围:
  >>> aList = []
  >>> aList[0]
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  IndexError: list index out of range
  请求一个不存在的字典关键字:
  >>> aDict = {'host':'earth','port':80}
  >>> print aDict['server']
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  KeyError: 'server'
  输入/输出错误
  >>> f = open('haha')
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  IOError: [Errno 2] No such file or directory: 'haha'
  尝试访问未知的对象属性

  >>>>  ...   pass
  ...
  >>> myInst = myClass()
  >>> myInst.bar = 'spam'
  >>> myInst.bar
  'spam'
  >>> myInst.foo
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  AttributeError: 'myClass' object has no attribute 'foo'
  10.3 检测和处理异常:
  异常可以通过try语句来检测,任何在try语句块里的代码都会被检测,检查有无异常发生
  try语句有两种形式:
  try-except和try-finally
  一个try语句可以对应一个或多个except子句,但只能对应一个finally子句,或一个try-except-finally复合语句
  10.3.1 try-except 语句
  try:
  try_suite # watch for exceptions here 监控这里的异常
  except Exception[,reason]:
  except_suite   # exception-handling code 异常处理代码
  例:
  >>> try:
  ...     f = open('haha','r')
  ... except IOError,e:
  ...     print 'could not open file:',e
  ...
  could not open file: [Errno 2] No such file or directory: 'haha'
  10.3.2 封装内建函数
  >>> float(12345)
  12345.0
  >>> float('12345')
  12345.0
  >>> float('123.45e67')
  1.2345e+69
  >>> float('foo')
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ValueError: could not convert string to float: foo
  >>> float(['this is',1,'list'])
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  TypeError: float() argument must be a string or a number
  如果参数类型正确,但值不可转换为浮点数,那么将引发ValueError异常
  安全的调用float()函数:
  我们创建一个封装函数,safe_float(),第一次改进中我们搜索并忽略ValueError
  >>> def safe_float(obj):
  ...     try:
  ...        return float(obj)
  ...     except ValueError:
  ...        pass
  ...
  >>> safe_float('haha')
  >>> safe_float('123')
  123.0
  以上不足在于出现错误无返回任何信息,我们至少应该显式的返回None
  >>> def safe_float(obj):
  ...     try:
  ...        retval = float(obj)
  ...     except ValueError:
  ...        retval = 'None'
  ...     return retval
  ...
  >>> safe_float('123')
  123.0
  >>> safe_float('haha')
  'None'
  >>>def safe_float(obj):
  ...     try:
  ...        retval = float(obj)
  ...     except ValueError:
  ...        retval = 'could not convert non-number to float'
  ...     return retval
  ...
  >>> safe_float('123')
  123.0
  >>> safe_float('bad input')
  'could not convert non-number to float'
  但如果传递一个非法对象,还是会出问题
  >>> safe_float({'a':'Dict'})
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in safe_float
  TypeError: float() argument must be a string or a number
  10.3.3 带有多个except的try语句
  except Exception1[, reason]:
  suite_for_exception_Exception1
  except Exception2[, reason]:
  suite_for_exception_Exception2
  例:
  >>> def safe_float(obj):
  ...     try:
  ...         retval = float(obj)
  ...     except ValueError:
  ...         retval = 'could not convert non-number to float'
  ...     except TypeError:
  ...         retval = 'object type cannot be converted to float'
  ...     return retval
  ...
  使用错误的参数调用这个函数:
  >>> safe_float('xyz')
  'could not convert non-number to float'
  >>> safe_float(())
  'object type cannot be converted to float'
  >>> safe_float(200L)
  200.0
  >>> safe_float(45.67000)
  45.670000000000002
  10.3.4 处理多个异常的except语句:
  except (Exception1,Exception2)[, reason]:
  suite_for_exception_Exception1_and_Exception2
  except (Exc1[,Exc2[, ... ExcN]])[, reason]:
  suite_for_exceptions_Exc1_and_ExcN
  要求safe_float()函数中的所有异常必须使用同样的代码:
  >>> def safe_float(obj):
  ...    try:
  ...       retval = float(obj)
  ...    except(ValueError,TypeError):
  ...       retval = 'argument must be a number or numeric string'
  ...    return retval
  ...
  现在,错误的输出会返回相同字符串:
  >>> safe_float('Spanish Inquisition')
  'argument must be a number or numeric string'
  >>> safe_float([])
  'argument must be a number or numeric string'
  >>> safe_float('1.6')
  1.6000000000000001
  >>> safe_float(1.6)
  1.6000000000000001
  >>> safe_float(932)
  932.0
  10.3.5 捕获所有异常:
  try:
  :
  except Exception,e:
  # error,occurred,log 'e',etc
  不推荐:
  try:
  :
  except Exception,e:
  # error,occurred,etc.
  捕获Python需要退出的异常:
  try:
  :
  except(KeyboardInterupt,SystemExit):
  # user wants to quit
  raise # reraise back to caller
  except Exception:
  # handle real errors
  当你有了一个Exception处理器后,你不必为这两个异常创建额外的处理器
  try:
  :
  except Exception,e:
  # handle real errors
  如果你确实需要捕获所有异常,那么你就得使用新的BaseExcption:
  try:
  :
  except BaseException,e:
  # handle all errors
  注: 不要处理并忽略所有错误
  try:
  large_block_of_code #bandage of large piece of code
  except Exception: # same as except:
  pass # blind eye ignoring all errors
  10.3.6 异常参数:
  # single exception
  except Exception[, reason]:
  suite_for_Exception_with_Argument
  # multiple exceptions
  except (Exception1,Exception2,...,ExceptionN)[, reason]:
  suite_for_Exception1_to_ExceptionN_wih_Argument
  例:传参给内建float函数一个无效对象,引发TypeError异常:
  >>> try:
  ...     float(['float() does not','like lists', 2])
  ... except TypeError,diag: # capture diagnostic info
  ...     pass
  ...
  >>> type(diag)
  <type 'exceptions.TypeError'>
  >>> print diag
  float() argument must be a string or a number
  我们首先在一个try语句块中引发一个异常,随后简单的忽略了这个异常,但保留了错误的信息,调用内置type()函数,我们可以确认我们的异常的确是TypeError异常类的实例,最后我们队异常诊断参数调用print以显示错误
  为了获取更多关于异常的信息,我们可以调用该实例的__class__属性,它标示了实例是从什么类实例化而来,类对象也有属性
  >>> diag
  TypeError('float() argument must be a string or a number',)
  >>> diag.__class__
  <type 'exceptions.TypeError'>
  >>> diag.__class__.__doc__
  'Inappropriate argument type.'
  >>> diag.__class__.__name__
  'TypeError'
  我们用字符串化(string representation)的异常参数来替换单一的错误信息
  >>> def safe_float(object):
  ...    try:
  ...       retval = float(object)
  ...    except(ValueError, TypeError), diag:
  ...       retval = str(diag)
  ...    return retval
  当我们提供的safe_float()参数给的不恰当时,虽然只有一条捕获语句,但可以获得如下信息:
  >>> safe_float('xyz')
  'could not convert string to float: xyz'
  >>> safe_float({})
  'float() argument must be a string or a number'
  10.3.7 在应用使用我们封装的函数:
  我们将在一个迷你应用中特地的使用这个函数,它将打开信用卡交易数据文件,加载所有交易,包括解释的字符串,下面是一个示例的carddate.txt文件:
  # cat carddata.txt
  # carddata.txt previous balance
  25
  debits
  21.64
  541.24
  25
  credits
  -25
  -541.24
  finance charge/late fees
  7.30
  5
  # vi cardrun.py
  ----------------------------
  #!/usr/bin/env python
  def safe_float(obj):
  'safe version of float()'
  try:
  retval = float(obj)
  except(ValueError,TypeError),diag:
  retval = str(diag)
  return retval
  def main():
  'handles all the data processing'
  log = open('cardlog.txt','w')
  try:
  ccfile = open('carddata.txt','r')
  except IOError,e:
  log.write('no txns this month\n')
  log.close()
  return
  txns = ccfile.readlines()
  ccfile.close()
  total = 0.00
  log.write('accout log:\n')
  for eachTxn in txns:
  result = safe_float(eachTxn)
  if isinstance(result,float):
  total += result
  log.write('data... processed\n')
  else:
  log.write('ignored: %s' %result)
  print '$%.2f(new balance)' % (total)
  log.close()
  if __name__ == '__main__':
  main()
  ----------------------------
  # python cardrun.py
  -------------------------
  $58.94(new balance)
  ---------------------------
  # cat cardlog.txt
  ------------------------------
  accout log:
  ignored: could not convert string to float: # carddata.txt previous balance
  data... processed
  ignored: could not convert string to float: debits
  data... processed
  data... processed
  data... processed
  ignored: could not convert string to float: credits
  data... processed
  data... processed
  ignored: could not convert string to float: finance charge/late fees
  data... processed
  data... processed
  ignored: could not convert string to float:
  ----------------------------------
  10.3.8 else 子句
  在try范围中没有异常被检测到时,才会执行else子句
  import 3rd_party_module
  log = open('logfile.txt','w')
  try:
  3rd_party_module.function()
  except:
  log.write("*** caught exception in module\n")
  else:
  log.write("*** no exception caught\n")
  log.close()
  10.3.9 finally子句
  try-except-else-finally语法示例:
  try:
  A
  except MyException: B
  else: C
  finally: D
  10.3.10 try-finally语句:
  无论try中是否有异常触发,finally代码段都会被执行
  try:
  try_suite
  finally:
  finally_suite # 无论如何都执行
  当在try范围中产生一个异常时,会立即跳转到finally语句段,当finally所有代码执行完毕,才会继续向上一层引发异常
  try:
  cofile = open('carddata.txt')
  except IOError:
  log.write('no txns this month\n')
  txns = cofile.readlines()
  ccfie,close
  但有很多原因会导致readlines()失败,其中一种就是carddata.txt存在于网络(或软盘上),本身介质的不稳定导致不能稳定读取
  我们可以把这一小段读取数据的代码整个放入try子句范围中:
  try:
  cofile = open('carddata.txt')
  txns = cofile.readlines()
  ccfie.close
  except IOError:
  log.write('no txns this month\n')
  如果出于一些原因readlines()调用失败,异常处理会去继续执行except中的子句,从而不会去关闭文件(ccfie.close)
  如何在出现错误后,仍旧可以关闭文件,我们可以通过try-finally来实现:
  ccfile = None
  try:
  try:
  cofile = open('carddata.etc')
  txns = cofile.readlines()
  ccfie.close
  except IOEorror:
  log.write('no txns this month\n')
  finally:
  if ccfile:
  ccffle.close()
  以下代码本质与之前干的同样的工作,区别在于关闭文件发生在异常处理器将错误写入日志之前,这是因为finally会自动重新引发异常
  ccfile = None
  try:
  try:
  cofile = open('carddata.etc')
  txns = cofile.readlines()
  finally:
  if ccfile:
  ccffle.close()
  except IOError:
  log.write('no txns this month\n')
  10.3.11 try-except-else-finally
  try:
  try_suite
  except Exception1:
  suite_for_Exception1
  except (Exception2,Exception3,Exception4):
  suite_for_Exceptions_2_3_and_4
  except Exception5,Argument5:
  suite_for_excetion5_plus_argument
  except (Exception6,Exception7),Argument67:
  suite_for_excetion6_and_7_plus_argument
  except:
  suite_for_all_other_exceptions
  else:
  no_exceptions_detected_suite
  finally:
  always_execute_suite
  10.4 上下文管理
  10.4.1 with语句
  with context_expr [as var]:
  with_suite
  例:
  with open('/etc/passwd','r') as f:
  for eachLine in f:
  # ...do stuff with eachLine or f...
  10.4.2 *上下文管理协议
  10.5 *字符串作为异常
  10.6 触发异常
  到目前为止,我们所见到的异常都是由解释器引发的,由于执行期间的错误而引发,程序员在编写API时也希望在遇到错误的输入时触发异常,为此,Python提供了一种机制让程序员明确的触发异常:这就是raise语句:
  10.6.1 raise语句
  raise [SomeException [, args[, traceback]]]
  raise语句的用法
  rasie 语法描述
  raise exclass触发一个异常,从exclass生成一个实例(不含任何异常参数)
  raise exclass()同上,除了现在不是类;通过函数调用操作符作用于类名生成一个新的exclass实例,同样也没有异常参数
  raise exclass,args同上,但同时提供的异常参数args,可以是一个参数也可以元祖
  raise exclass(args)同上
  raise exclass,args, tb同上,但提供一个追踪对象tb供使用
  raise exclass,instance通过实例触发异常
  raise instance通过实例触发异常
  raise string触发字符串异常
  raise string,args触发伴随着args
  raise string,args,tb同上,但提供一个追踪对象tb供使用
  raise重新触发前一个异常,如果之前没有异常,触发TypeError
  10.7 断言
  断言是一句必须等价于布尔真的判定,此外,发生异常也意味着表达式为假
  可以理解为是raise-if-not语句,如果返回值是假,触发异常
  10.7.1 断言语句
  assert expression[, arguments]
  assert用法:
  assert 1 == 1
  assert 2 +2 == 2 * 2
  assert len(['my list', 12]) < 10
  assert range(3) == [0, 1, 2]
  AssertionError异常和其他异常一样可以用try-except语句块捕捉,如果没有捕捉,它将终止程序运行而且提供一个如下的traceback:
  >>> assert 1 == 0
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  AssertionError
  我们可以提供一个异常参数给我们的assert命令:
  >>> assert 1 == 0 , 'One dose not equal zero silly!'
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  AssertionError: One dose not equal zero silly!
  用try-except语句捕获AssertionError异常:
  >>> try:
  ...     assert 1 == 0, 'One does not equal zero silly!'
  ... except AssertionError,args:
  ...     print '%s: %s' %(args.__class__.__name__, args)
  ...
  AssertionError: One does not equal zero silly!
  例:
  def assert(expr, args=None):
  if __debug__ and not expr:
  raise AssertionError,args
  10.8 标准异常:
  表10.2 列出了所有的Python当前的标准异常集,所有的异常都是内建的,所以它们在脚本启动前或在互交命令行提示符出现时已经是可用的了
  表10.2 Python内建异常
  (略)
  10.9 创建异常:
  例:
  --------------------------------------
  #!/usr/bin/env python
  import os,socket,errno,types,tempfile
  class NetworkError(IOError):
  pass
  class FileError(IOError):
  pass
  def updArgs(args,newarg=None):
  if isinstance(args,IOError):
  myargs = []
  myargs.extend([arg for arg in args])
  else:
  myargs = list(args)
  if newarg:
  myargs.append(newarg)
  return tuple(myargs)
  def fileArgs(file, mode, args):
  if args[0] == errno.EACCES and 'access' in dir(os):
  perms = ''
  permd = {'r': os.R_OK, 'w': os.W_OK, 'x': os.X_OK}
  pkeys = permd.keys()
  pkeys.sort()
  pkeys.reverse()
  for eachPerm in 'rwx':
  if os.access(file, permd[eachPerm]):
  perms += eachPerm
  else:
  perms += '-'
  if isinstance(args,IOError):
  myargs = []
  myargs.extend([arg for arg in args])
  else:
  myargs = list(args)
  myargs[1] = "'%s' %s (perms: '%s')" %(mode,myargs[1],perm)
  myargs.append(args.filename)
  else:
  myargs = args
  return tuple(myargs)
  def myconnect(sock,host,port):
  try:
  sock.connect((host,port))
  except socket.error, args:
  myargs = updArgs(args)
  if len(myargs) == 1:
  myargs = (errno,ENXIO, myargs[0])
  raise NetworkError, updArgs(myargs, host + ':' + str(port))
  def myopen(file,mode='r'):
  try:
  fo = open(file,mode)
  except IOError,args:
  raise FileError, fileArgs(file, mode, args)
  return fo
  def testfile():
  file =  tempfile.mktemp()
  f = open(file,'w')
  f.close()
  for eachTest in ((0, 'r'), (0100, 'r'),(0400,'w'),(0500, 'w')):
  try:
  os.chmod(file, eachTest[0])
  f = myopen(file, eachTest[1])
  except FileError, args:
  print "%s: %s" %(args.__class__.__name__, args)
  else:
  print file, "opened ok... perm ignored"
  f.close()
  os.chmod(file,0777)
  os.unlink(file)
  def testnet():
  s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  for eachHost in ('deli', 'www'):
  try:
  myconnect(s, 'deli', 8080)
  except NetworkError, args:
  print "%s: %s" %(args.__class__.__name__, args)
  if __name__ == '__main__':
  testfile()
  testnet()
  --------------------------------------
  10.10 为什么用异常(现在)?
  10.11 到底为什么要异常?
  10.12 异常和sys模块
  >>> try:
  ...     float('abc123')
  ... except:
  ...     import sys
  ...     exc_tuple = sys.exc_info()
  ...
  >>> print exc_tuple
  (<type 'exceptions.ValueError'>, ValueError('could not convert string to float: abc123',), <traceback object at 0x7f1412e09fc8>)
  >>>
  >>> for eachItem in exc_tuple:
  ...     print eachItem
  ...
  <type 'exceptions.ValueError'>
  could not convert string to float: abc123
  <traceback object at 0x7f1412e09fc8>
  我们从sys.exc_info()得到的元祖中是:
  exc_type: 异常类
  exc_value: 异常类的实例
  exc_traceback: 追踪对象
  10.13 相关模块
  模块描述
  exceptions内建异常(永远不用导入这个模块)
  contectliba为使用with语句的上下文对象工具
  sys包含各种异常相关的对象和函数

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-546337-1-1.html 上篇帖子: Python3.6 和 Pycharm 详细安装教程 下篇帖子: linux下安装python 3.6
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表