(转)Python自动化运维之13、异常处理及反射(__import__,getattr,hasattr,setattr)

原文:http://www.cnblogs.com/xiaozhiqi/p/5778856.html

https://blog.csdn.net/zong596568821xp/article/details/78180229------Python异常捕获与处理

 

一、异常处理

python异常:
  python的运行时错误称作异常
  (1)语法错误:软件的结构上有错误而导致不能被解释器解释或不能被编译器编译
  (2)逻辑错误:由于不完整或不合法的输入所致,也可能是逻辑无法生成、计算或者输出结果需要的过程无法执行等

python异常是一个对象,表示错误或意外情况
  (1)在python检测到一个错误时,将触发一个异常
    python可以通常异常传导机制传递一个异常对象,发出一个异常情况出现的信号
    程序员也可以在代码中手动触发异常
  (2)python异常也可以理解为:程序出现了错误而在正常控制流以外采取的行为
    第一阶段:解释器触发异常,此时当前程序流将被打断
    第二阶段:异常处理,如忽略非致命错误、减轻错误带来的影响等

检测和处理异常:
  (1)异常通过try语句来检测
    任何在try语句块里的代码都会被检测,以检查有无异常发生
  (2)try语句主要有两种形式:
    try-except: 检测和处理异常
      可以有多个except
      支持使用else子句处理没有探测异常的执行的代码
    try-finally: 仅检查异常并做一些必要的清理工作
      仅能有一个finally
  (3)try语句的复合形式:
    try-execpt-else-finally

 

1、异常基础

在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大黄页!!!

1
2
3
4
try:
    pass
except Exception as ex:  
    pass

#python3.x中是这么写的,python2.x是这么写的:  except Exception,e:

需求:将用户输入的两个数字相加  

复制代码
while True:
    num1 = raw_input('num1:')
    num2 = raw_input('num2:')
    try:
        num1 = int(num1)
        num2 = int(num2)
        result = num1 + num2
    except Exception as e:
        print('出现异常,信息如下:')
        print(e)
复制代码

2、异常种类

python中的异常种类非常多,每个异常专门用于处理某一项异常!!!

复制代码
AssertionError: 断言语句失败
AttributeError: 属性引用或赋值失败
FloatingPointError: 浮点型运算失败
IOError:  I/O操作失败
ImportError: import语句不能找到要导入的模块,或者不能找到该模块特别请求的名称
IndentationError: 解析器遇到了一个由于错误的缩进而引发的语法错误
IndexError: 用来索引序列的证书超出了范围
KeyError: 用来索引映射的键不再映射中
keyboardInterrupt: 用户按了中断键(Ctrl+c,Ctrl+Break或Delete键)
MemoryError: 运算耗尽内存
NameError: 引用了一个不存在的变量名
NotImplementedError: 由抽象基类引发的异常,用于指示一个具体的子类必须覆盖一个方法
OSError: 由模块os中的函数引发的异常,用来指示平台相关的错误
OverflowError: 整数运算的结果太大导致溢出
SyntaxError: 语法错误
SystemError: python本身或某些扩展模块中的内部错误
TypeError:对某对象执行了不支持的操作
UnboundLocalError:引用未绑定值的本地变量
UnicodeError:在Unicode的字符串之间进行转换时发生的错误
ValueError:应用于某个对象的操作或函数,这个对象具有正确的类型,但确有不适当的值
WindowsError:模块os中的函数引发的异常,用来指示与WIndows相关的错误
ZeroDivisionError: 除数为0
复制代码
 更多异常

实例:IndexError

dic = ["python", 'linux']
try:
    dic[10]
except IndexError as e:
    print(e)

实例:KeyError

dic = {'k1':'v1'}
try:
    dic['k20']
except KeyError as e:
    print(e)

对于上述实例,异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。

1
2
3
4
5
6
7
# 未捕获到异常,程序直接报错
  
s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print(e)

所以,写程序时需要考虑到try代码块中可能出现的任意异常,可以这样写:  

1
2
3
4
5
6
7
8
9
s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print(e)
except KeyError as e:
    print(e)
except ValueError as e:
    print(e)

万能异常 在python的异常中,有一个万能异常:Exception,他可以捕获任意异常,即:  

1
2
3
4
5
s1 = 'hello'
try:
    int(s1)
except Exception as e:
    print(e)

接下来你可能要问了,既然有这个万能异常,其他异常是不是就可以忽略了!

答:当然不是,对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行

1
2
3
4
5
6
7
8
9
s1 = 'hello'
try:
    int(s1)
except KeyError as e:
    print('键错误')
except IndexError as e:
    print('索引错误')
except Exception as e:
    print('错误')

3、异常其他结构  

1
2
3
4
5
6
7
8
9
10
11
12
try:
    # 主代码块
    pass
except KeyError as e:
    # 异常时,执行该块
    pass
else:
    # 主代码块执行完,执行该块
    pass
finally:
    # 无论异常与否,最终执行该块
    pass

4、主动触发异常  

1
2
3
4
try:
    raise Exception('错误了。。。')
except Exception as e:
    print(e)

5、自定义异常  

1
2
3
4
5
6
7
8
9
10
11
12
class MyException(Exception):
  
    def __init__(self, msg):
        self.message = msg
  
    def __str__(self):
        return self.message
  
try:
    raise MyException('我的异常')
except WupeiqiException as e:
    print(e)

6、断言  

1
2
3
4
5
# assert 条件
  
assert 1 == 1
  
assert 1 == 2

二、反射

  python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr、__import__(module_name),改四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员、导入模块以字符串方式导入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Foo(object):
  
    def __init__(self):
        self.name = 'python'
  
    def func(self):
        return 'func'
  
obj = Foo()
  
# #### 检查是否含有成员 ####
hasattr(obj, 'name')
hasattr(obj, 'func')
  
# #### 获取成员 ####
getattr(obj, 'name')
getattr(obj, 'func')
  
# #### 设置成员 ####
setattr(obj, 'age'18)
setattr(obj, 'show'lambda num: num + 1)
  
# #### 删除成员 ####
delattr(obj, 'name')
delattr(obj, 'func')

详细解析:

当我们要访问一个对象的成员时,应该是这样操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Foo(object):
  
    def __init__(self):
        self.name = 'python'
  
    def func(self):
        return 'func'
  
obj = Foo()
  
# 访问字段
obj.name
# 执行方法
obj.func()
那么问题来了?
a、上述访问对象成员的 name 和 func 是什么? 
答:是变量名
b、obj.xxx 是什么意思? 
答:obj.xxx 表示去obj中或类中寻找变量名 xxx,并获取对应内存地址中的内容。
c、需求:请使用其他方式获取obj对象中的name变量指向内存中的值 “python”
复制代码
class Foo(object):
 
    def __init__(self):
        self.name = 'python'
 
# 不允许使用 obj.name
obj = Foo()
复制代码

答:有两种方式,如下:

复制代码
class Foo(object):

    def __init__(self):
        self.name = 'python'

    def func(self):
        return 'func'

# 不允许使用 obj.name
obj = Foo()

print obj.__dict__['name']
复制代码

第二种:

复制代码
class Foo(object):

    def __init__(self):
        self.name = 'python'

    def func(self):
        return 'func'

# 不允许使用 obj.name
obj = Foo()

print getattr(obj, 'name')
复制代码

d、比较三种访问方式

  • obj.name
  • obj.__dict__['name']
  • getattr(obj, 'name')

答:第一种和其他种比,...
      第二种和第三种比,...

复制代码
#!/usr/bin/env python
#coding:utf-8
from wsgiref.simple_server import make_server

class Handler(object):

    def index(self):
        return 'index'

    def news(self):
        return 'news'


def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    url = environ['PATH_INFO']
    temp = url.split('/')[1]
    obj = Handler()
    is_exist = hasattr(obj, temp)
    if is_exist:
        func = getattr(obj, temp)
        ret = func()
        return ret
    else:
        return '404 not found'

if __name__ == '__main__':
    httpd = make_server('', 8001, RunServer)
    print "Serving HTTP on port 8000..."
    httpd.serve_forever()
复制代码

结论:反射是通过字符串的形式操作对象相关的成员。一切事物都是对象!!!

  

类也是对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Foo(object):
  
    staticField = "old boy"
  
    def __init__(self):
        self.name = 'wupeiqi'
  
    def func(self):
        return 'func'
  
    @staticmethod
    def bar():
        return 'bar'
  
print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')

模块也是对象

home.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def dev():
    return 'dev'

 index.py

复制代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
"""
程序目录:
    home.py
    index.py
 
当前文件:
    index.py
"""
 
 
import home as obj
 
#obj.dev()
 
func = getattr(obj, 'dev')
func() 
复制代码

两个例子:

第一个例子:模块和主程序在同一目录

home.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def index():
    print("炫酷的主页面")

index.py

复制代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 反射:基于字符串的形式去对象(模块)中操作其成员getattr(),setattr(),hasattr(),delattr()
# 扩展:导入模块
#      import xxx
#      from xxx import ooo
#
#      obj = __import__("xxx")
#      obj = __import__("xxx." + ooo,fromlist=True)


def run():
    while True:
        inp = input("请输入要访问的URL:")
        mo,fn = inp.split('/')
        obj = __import__(mo)
        if hasattr(obj,fn):
            func = getattr(obj,fn)
            func()
        else:
            print("网页不存在")

run()
复制代码

执行的时候输入URL:home/index   这样就执行了home模块下的index函数

第二个例子:模块和主程序不在同一目录

lib/account.py  

复制代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-

def login():
    print("炫酷的登录页面")


def logout():
    print("炫酷的退出页面")
复制代码

index1.py

复制代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-

# 反射:基于字符串的形式去对象(模块)中操作其成员getattr(),setattr(),hasattr(),delattr()
# 扩展:导入模块
#      import xxx
#      from xxx import ooo
#
#      obj = __import__("xxx")
#      obj = __import__("xxx." + ooo,fromlist=True)

def run():
    while True:
        inp = input("请输入要访问的URL:")
        mo,fn = inp.split('/')
        obj = __import__("lib." + mo,fromlist=True)
        if hasattr(obj,fn):
            func = getattr(obj,fn)
            func()
        else:
            print("网页不存在")


run()
复制代码

执行的时候输入URL:account/login 这样就执行了lib/account下的login函数

posted @ 2017-08-21 15:01  liujiacai  阅读(520)  评论(0编辑  收藏  举报