码迷,mamicode.com
首页 > 编程语言 > 详细

python学习------------异常以及反射

时间:2016-01-21 20:10:34      阅读:339      评论:0      收藏:0      [点我收藏+]

标签:python基础

    学完这一节,python基础部分就要告一段落了,期待进入新一阶段的学习,也给自己说坚持就是胜利。

一、isinstance(obj,cls)

检查obj是否是cls的对象

1、首先从学过的变量开始

a = 12
b = "bb"
print isinstance(a,int) #结果是True
print isinstance(a,str) #结果是False
print isinstance(b,str) #结果是True
print isinstance(b,int) #结果是False

其实也就是说:变量a,b是对象,是否是属于int,str的类,属于返回True,不属于返回False

2、类中的对象和类之间的关系

class Foo:
    def __init__(self):
        pass

    def func(self):
        pass

obj = Foo()
print isinstance(obj,Foo) #结果是True

3、对象和基类的关系

class Foo:
    def __init__(self):
        pass

    def func(self):
        pass
class Bar(Foo):
    pass

obj = Bar()
print isinstance(obj,Bar) #结果为True
print isinstance(obj,Foo) #结果是True

总结:

  • isinstance是判断一个对象是否属于类

  • 就是对象和类的关系

  • 对象和基类的关系

二、issubclass(sub,super)

检查sub是否是super的派生类

class Foo:
    def __init__(self):
        pass

    def func(self):
        pass
class Bar(Foo):
    pass

print issubclass(Bar,Foo) #结果为True

三、异常处理

1、产生的缘由

    为了在编程过程中,增加和用户交互的友好性,在程序出现错误时不将错误信息显示给用户,也就是不会出现我们通常浏览页面时出现的大黄页,而是显示一个错误提示的界面。

2、在python中处理异常的方法 

try:
    pass
except Exception e:
    pass

在try中是正确的逻辑代码

在except中是代码逻辑块出现错误

例如:

input = raw_input("input:")
data = int(input)
try:
    input = raw_input("input:")
    data = int(input)
except Exception,e:
    print "请输入数字"

在一块代码中,加入我输入数字,程序不会报错,而当我输入字母时,程序就会报错。

而在加了try和except块的代码时,当输入数字时,程序依然不会报错,而输入非数字时就会打印提示信息,让你输入数字。

通过以上对比,可以看出加了异常处理的代码比没加异常处理的代码的用户交互的友好性提高了很多。

3、异常的种类

1)、指定的异常

dic = {‘k1‘:‘v1‘,‘k2‘:‘v2‘}
try:
    dic[‘k3‘]
except KeyError,e:
       print e
dic = ["tom", ‘bb‘]
try:
    dic[10] 
except IndexError, e:
    print e
#list index out of range
s1 = ‘hello‘
try:
    int(s1)
except ValueError, e:
    print e
#invalid literal for int() with base 10: ‘hello‘


上述代码异常都是指定的是特定的错误处理,例如key,index,value等,但是这样处理也会存在一定的问题,例如:

#假如你写成下面的异常处理,程序未能捕获出异常,程序直接报错
s1 = ‘hello‘
try:
    int(s1)
except IndexError,e:
    print e

针对这样的问题,一般我们处理异常时一般写成如下的异常处理顺序

s1 = ‘hello‘
try:
    int(s1)
except IndexError,e:
    print e
except KeyError,e:
    print e
except ValueError,e:
    print e
except Exception,e:
    print e

也就是说先写特殊的,最后写最终的Exception,Exception也被叫做万能异常,可以捕获任意异常。

但是反过来会说,既然有了万能异常可以捕获任意的异常,还需要特殊异常做什么?

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

总结一下特殊的异常

ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError

4、异常的大结构

try:
    #主代码块,逻辑代码
    pass
except IndexError,e:#异常处理
    pass
except Exception,e:
    pass
else:
    #逻辑块中未出现异常,主代码块执行完后执行
    pass
finally:
    #永远执行,逻辑代码执行完后执行
    pass

5、主动触发异常

#导入另外一个模块,然后调用其中的方法
import helper  #helper里有方法f1(),返回一个值
if __name__ == "__main__":
  try:
     n = "1"
     n = int(n)
     IndexError
     ret = helper.f1()
     if ret:
         print "成功"
     else:
         #出现错误
         raise Exception("出现错误")
  except Exception,e:
      print "出现错误"
      print e

如果返回的值为假,则就会主动触发错误,即raise Exception("出现错误")

小结:

1、以上关于异常的处理中,都会有一个e:它的作用是什么?

答案:e是对象,将IndexError等都封装到e中,相当于类中的字段封装的对象中。

2、Exception和这些特殊的处理IndexError是什么关系?

答案:Exception是他们的基类。

3、为什么下面的异常会打印这样的提示?

try:
   int("aa")
except Exception,e:
   print e
#异常结果为:invalid literal for int() with base 10: ‘aa‘

首先给出答案:它是由类中的__str__方法产生的

例如:

class A:
     pass
obj = A()
print obj
#结果为<__main__.A instance at 0x023EF7B0>

这样可以看出我们在异常中print e的结果是一个字符串,而在类中print 对象是内存地址,那怎么做才能和print e一致呢?

class A:
    def __str__(self):
        return "aa"
obj = A()
print obj
#结果为aa

在类中加入__str__方法,再次print 对象,就会打印一个字符串,这就和在异常中打印invalid literal for int() with base 10: ‘aa‘原理一样了。

本质为:在异常中e是对象,而Exception是类,也就是对象e调用类Exception中的__str__方法得到的结果。

6、自定义异常

#类crazyException继承了类Exception
class crazyException(Exception):
    #将msg封装到对象e中
    def __init__(self, msg= None):#初始值msg为None
        self.message = msg

    def __str__(self):
        if self.message:
             return self.message
        else:
             return ‘crazyException‘

try:
    raise crazyException(‘我的异常‘)
except Exception,e:
    print e

7、断言:assert

作用在程序调试时,判断程序是否正确,用于debug

assert 条件

如果条件为真,不会报错,否则,程序报错

例如:

assert 1==1

assert 1==2

四、反射

1、python中的反射功能是由四种内置函数来提供的,hasattr,setattr,getattr,delattr这四个内置函数分别用于对对象内部执行:检查是否含有某成员,设置某成员,获取某成员,删除成员

class Foo(object):

    def __init__(self):
        self.name = ‘tom‘

    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‘)

2、下面通过例子一步步的讨论反射:

1)、我们模拟web为例

home.py

def index():
    return ‘home.index‘

def dev():
    return ‘home.dev‘
import home
url = raw_input("url:")
if url == "home/dev":
    ret = home.dev()
    print ret
elif url == "home/index":
    ret = home.index()
    print ret
else:
    print "404"

这就是说我们输入对应的url,再进行判断找到符合条件的url,返回值

下面我们采用反射来进行操作

url = raw_input("url:")
#url = home/dev
controller,action = url.split(‘/‘)
import home
#action = 字符串
#去某个容器或模块中,找函数,字符串是函数名,如果有,则获取函数
func = getattr(home,action)
#在home中找action,如果有则返回函数名
ret = func()#函数名加括号,表示执行函数,返回结果ret
print ret

这样一来在上面的代码中就不需要再进行判断,只需去在home模块中寻找符合的url,这对于大量的url来说,用反射就简单了。

2)对四种内置函数产生的结果进行比较

import home
print dir(home)#结果为[‘__builtins__‘, ‘__doc__‘, ‘__file__‘, ‘__name__‘, ‘__package__‘, ‘dev‘, ‘index‘]
print hasattr(home,‘dev‘)#结果为True
print getattr(home,‘dev‘)#结果<function dev at 0x026072F0>

setattr(home,‘show‘,lambda x : x + 1)
print dir(home)
#结果为[‘__builtins__‘, ‘__doc__‘, ‘__file__‘, ‘__name__‘, ‘__package__‘, ‘dev‘, ‘index‘, ‘#show‘]
#多了show
delattr(home,‘show‘)
print dir(home)
#结果为[‘__builtins__‘, ‘__doc__‘, ‘__file__‘, ‘__name__‘, ‘__package__‘, ‘dev‘, ‘index‘]
#将show删除了

3)在web上进行测试(练习反射)

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

def RunServer(environ, start_response):
    start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html‘)])
    url = environ[‘PATH_INFO‘]
    temp = url.split(‘/‘)[1]
    import home
    #去home模块中检查,是否含有指定的函数
    is_exist = hasattr(home, temp)
    #如果存在指定的函数
    if is_exist:
        #获取函数
        func = getattr(home, temp)
        #执行函数并获取返回值
        ret = func()
        #将函数返回值响应给请求者
        return ret
    else:
        return ‘404 not found‘

if __name__ == ‘__main__‘:
    httpd = make_server(‘‘, 8001, RunServer)
    print "Serving HTTP on port 8001..."
    httpd.serve_forever()

3、反射操作类和对象中的成员

class Foo:
    static_name = ‘tom‘
    def __init__(self):
        self.name = "eric"

    def show(self):
        pass
    @staticmethod
    def static_method():
        pass
    @classmethod
    def class_show(cls):
        pass
#先看类中都有什么方法
print Foo.__dict__.keys()
#[‘__module__‘, ‘static_method‘, ‘show‘, ‘static_name‘, ‘class_show‘, ‘__doc__‘, ‘__init__‘]
print hasattr(Foo,‘class_show‘) #看类中是否有class_show方法
obj = Foo()
#看对象中有什么,结果为{‘name‘: ‘eric‘}
print obj.__dict__
print hasattr(obj,‘name‘) #结果为True
print hasattr(obj,‘show‘) #结果为True

为什么对象中只有name,而用hasattr(obj,‘show‘)却显示为True,因为对象中存在类对象指针,对象首先在自己的内存中找,如果没有找到再到类中找,所以就会显示找到,返回结果为True

4、上面的操作都是在自己模块的内部执行,接下来看在其他模块执行效果

import home
cls = getattr(home,‘Foo‘)
print cls #home.Foo 得到是类
obj = cls() #cls是类,类加括号就是实例化,也就是创建对象,执行__init__方法
name = getattr(obj,‘name‘) #在对象中找name
print name

一句话总结反射:在容器中找对象的元素

5、动态导入模块

try:
    controller,action = raw_input("url:").split("/")
    module = __import__(controller)
    func = getattr(module,action)
    ret = func()
    print ret
except Exception,e:
    print "请正确输入url"

五、单例模式

单例就是单个实例

单例模式存在的目的就是保证内存中只存在一个实例,避免内存浪费

用两个例子对比说明单例模式

1、不使用单例模式

class SqlHelper:

    def __init__(self,name):
        self.name = "tom"
        self.name = name

    def show(self):
        pass

obj1 = SqlHelper(1)
print id(obj1) #37025832
obj2 = SqlHelper(1)
print id(obj2) #37195368

这样创建实例SqlHelper(1),但生成的id不同,占用大量内存。

2、采用单实例模式

class SqlHelper:

    __static_instance = None  
    def __init__(self):
        self.hostname = ‘0.0.0.0‘
        self.port = 3306
        self.user = ‘root‘

    @classmethod
    def instance(cls):
        #cls = SqlHelper
        if cls.__static_instance:
            return cls.__static_instance
        else:
            cls.__static_instance = SqlHelper()
            return cls.__static_instance
obj1 = SqlHelper.instance()
print id(obj1) #38833768
obj2 = SqlHelper.instance()
print id(obj2) #38833768

1、创建静态字段__static_instance = None 保存永远存在内存的实例

2、调用类方法@classmethod,返回那个对象

3、通过类对象获取永远存在内存的实例

这就是创建单例模式的要点。。。。。


参考来源:

http://www.cnblogs.com/wupeiqi/

以及老男孩python开发视频

本文出自 “crazyforever” 博客,请务必保留此出处http://crazyforever.blog.51cto.com/7362974/1737341

python学习------------异常以及反射

标签:python基础

原文地址:http://crazyforever.blog.51cto.com/7362974/1737341

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!