python之路[7] - 面向对象编程进阶、异常处理 - 迁

面向对象高级语法部分

经典类vs新式类

# 新式类
class A(object):
    def __init__(self, a):
        self.a = a
    def my_func(self):
        self.a += 1
        return self.a

# 经典类
class A:
    def test():
          ....

   

classical vs new style:

  • 经典类:深度优先 -- 先在第一个继承的父类里找
  • 新式类:广度优先  -- 先在同一层父类里面找
  • super()用法  -- 被继承的父类也要是新式类
新式类的继承
class B(A):
def __init__(self):
super(B, self).__init__(*args,**kwargs)

经典类的继承
class B(A):
def __init__(self):
A.__init__(self)

  

抽象类

抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化,抽象类是从一堆中抽取相同的内容而来的,内容包括数据属性和函数属性.

python2的写法

import abc
 
class Alert(object):
    '''报警基类'''
    __metaclass__ = abc.ABCMeta
 
    @abc.abstractmethod
    def send(self):
        '''报警消息发送接口'''
        pass
 
 
 
class MailAlert(Alert):
    pass
 
 
m = MailAlert()
m.send()

 

 python3

#一切皆文件
import abc #利用abc模块实现抽象类

class All_file(metaclass=abc.ABCMeta):
    all_type='file'
    @abc.abstractmethod #定义抽象方法,无需实现功能
    def read(self):
        '子类必须定义读功能'
        pass

    @abc.abstractmethod #定义抽象方法,无需实现功能
    def write(self):
        '子类必须定义写功能'
        pass

class Txt(All_file):
    pass

t1=Txt() #报错,子类没有定义抽象方法
# TypeError: Can't instantiate abstract class Txt with abstract methods read, write #


class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('文本数据的读取方法')

    def write(self):
        print('文本数据的读取方法')

class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('硬盘数据的读取方法')

    def write(self):
        print('硬盘数据的读取方法')

class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('进程数据的读取方法')

    def write(self):
        print('进程数据的读取方法')

wenbenwenjian=Txt()

yingpanwenjian=Sata()

jinchengwenjian=Process()

#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()

print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)

  

接口类

在接口类中,任何方法都只是一种规范,具体的功能需要子类实现
比如定义一个基类动物类(呼吸,心跳),狗,猫类去继承这个接口类,从而统一实现了各个动物的行为

  

 

静态方法 staticmethod

通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法 

静态方法使用场景

1 直接被外部调用,跟这个类本身没关系

class check_factor(object):
    def check_hostname(self, hostname):
        do_something_get_ip
 
    @staticmethod
    def check_hostnameIPwithPortVaild(hostnameIpWithPort):
        try:
            ret = check_factor().check_hostname(hostnameIp)  # 调用本类中方法,先执行实例化
        except Exception as e:
            print str(e)
        finally:
            return ret

    def host_health(self, hostnameIpWithPort):
        check_ret = check_factor.check_hostnameIPwithPortVaild(hostnameIpWithPort)  # 调用本类中的静态方法,直接调用即可

print cf.host_health('10.0.0.1:8777')
print check_factor.check_hostnameIPwithPortVaild('10.0.0.1:8777')

  

类方法  classmethod

类方法通过@classmethod装饰器实现,类方法使用场景:

1 类方法只能访问类变量,不能访问实例变量

2 类方法一般用在重写__init__的方法,这样做的好处就是不用管init里面逻辑,但是其他方法依然可以使用

class Dog(object):
    name = "我是类变量"
    def __init__(self,name):
        self.name = name
 
    @classmethod
    def eat(self):
        print("%s is eating" % self.name)
 
 
 
d = Dog("ChenRonghua")
d.eat()
 
 
#执行结果
 
我是类变量 is eating

 

 

综合应用

class Person:
    def __init__(self):
    print "init"
    
    @staticmethod //可以像函数一样被调用,而不用先实例化
    def sayHello(hello):
        if not hello:
            hello='hello'
        print "i will sya %s" %hello
@classmethod
// clazz可以调用类中的函数 def introduce(clazz,text): clazz.sayHello(text) print "from introduce method"

def hello(self,hello): self.sayHello(hello) print "from hello method"

Person.sayHello("haha") Person.introduce("hello world!") #Person.hello("self.hello") #TypeError: unbound method hello() must be called with Person instance as first argument (got str instance instead)​

init
i will sya haha
i will sya hello world!
from introduce method
i will sya self.hello
from hello method

 

 

相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。

不同点:方法调用者不同、调用方法时自动传入的参数不同。

 

属性方法 property

属性方法的作用就是通过@property把一个方法变成一个静态属性

class Dog(object):
 
    def __init__(self,name):
        self.name = name
 
    @property
    def eat(self):
        print(" %s is eating" %self.name)
 
 
d = Dog("ChenRonghua")
d.eat

输出
ChenRonghua is eating 

 

 

好吧,把一个方法变成静态属性有什么卵用呢?既然想要静态变量,那直接定义成一个静态变量不就得了么?well, 以后你会需到很多场景是不能简单通过 定义 静态属性来实现的, 比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步:

1. 连接航空公司API查询

2. 对查询结果进行解析 

3. 返回结果给你的用户

因此这个status属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以

class Flight(object):
    def __init__(self,name):
        self.flight_name = name


    def checking_status(self):
        print("checking flight %s status " % self.flight_name)
        return  1

    @property
    def flight_status(self):
        status = self.checking_status()
        if status == 0 :
            print("flight got canceled...")
        elif status == 1 :
            print("flight is arrived...")
        elif status == 2:
            print("flight has departured already...")
        else:
            print("cannot confirm the flight status...,please check later")


f = Flight("CA980")
f.flight_status
航班查询

那现在我只能查询航班状态, 既然这个flight_status已经是个属性了, 那我能否给它赋值呢?

f = Flight("CA980")
f.flight_status
f.flight_status =  2

输出:
checking flight CA980 status
flight is arrived...
Traceback (most recent call last):
  File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/属性方法.py", line 58, in <module>
    f.flight_status =  2
AttributeError: can't set attribute

 

 

当然可以改, 不过需要通过@proerty.setter装饰器再装饰一下,此时 你需要写一个新方法, 对这个flight_status进行更改。

class Flight(object):
    def __init__(self,name):
        self.flight_name = name


    def checking_status(self):
        print("checking flight %s status " % self.flight_name)
        return  1


    @property
    def flight_status(self):
        status = self.checking_status()
        if status == 0 :
            print("flight got canceled...")
        elif status == 1 :
            print("flight is arrived...")
        elif status == 2:
            print("flight has departured already...")
        else:
            print("cannot confirm the flight status...,please check later")
    
    @flight_status.setter #修改
    def flight_status(self,status):
        status_dic = {
: "canceled",
:"arrived",
: "departured"
        }
        print("\033[31;1mHas changed the flight status to \033[0m",status_dic.get(status) )

    @flight_status.deleter  #删除
    def flight_status(self):
        print("status got removed...")

f = Flight("CA980")
f.flight_status
f.flight_status =  2 #触发@flight_status.setter 
del f.flight_status #触发@flight_status.deleter

 

注意以上代码里还写了一个@flight_status.deleter, 是允许可以将这个属性删除 

 

class Pager:
    def __init__(self, current_page):
        # 用户当前请求的页码(第一页、第二页...)
        self.current_page = current_page
        # 每页默认显示10条数据
        self.per_items = 10 

    @property
    def start(self):
        val = (self.current_page - 1) * self.per_items
        return val

    @property
    def end(self):
        val = self.current_page * self.per_items
        return val

# ############### 调用 ###############

p = Pager(1)
p.start 就是起始值,即:m
p.end   就是结束值,即:n
分页应用

 

class Check_pm_health(object):
    today_time = time.strftime("%Y%m%d", time.localtime())
    def __init__(self,weaid):
        self.weaid = weaid # 城市ID
        self.params = {
            'app': 'weather.history',
            'appkey': '10003',
            'weaid': self.weaid, #bj:101010100 ,sh:101020100
            'date': self.today_time,
            'sign': 'b59bc3ef6191eb9f747dd4e83c99f2a4',
            'format': 'json',
 
        }
 
    @property
    def test(self): # 默认查询上海天气/也可以更具当前的地理位置查询当前所在的天气
        result = requests.get(params=self.params, url="http://api.k780.com:88")  # params url post 参数
        a = result.json()
        json.dump(a, open("wather.json", "w", encoding="utf8"), indent=4, ensure_ascii=False)
        b = a.get("result")
        print(  (b[0]['aqi'])) # 返回当天的天气值
 
    @test.setter
    def test(self,newcity): # 自定义天气查询
        self.params['weaid'] = newcity
        self.test
 
        
 
 
a = Check_pm_health(101010100)
a.test
a.test = 101020100
获取天气

 

 

类的特殊成员方法

1. __doc__  表示类的描述信息

class Foo:
    """ 描述类信息,这是用于看片的神奇 """
 
    def func(self):
        pass
 
print Foo.__doc__
#输出:类的描述信息
View Code

2. __module__ 和  __class__ 

  __module__ 表示当前操作的对象在那个模块

  __class__     表示当前操作的对象的类是什么

 

lib/aa.py
class C:

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

 

from lib.aa import C

obj = C()
print obj.__module__  # 输出 lib.aa,即:输出模块
print obj.__class__      # 输出 lib.aa.C,即:输出类
index.py

 

3. __init__ 构造方法,通过类创建对象时,自动触发执行。

4.__del__

 析构方法,当对象在内存中被释放时(可以理解为对象被使用完毕退出),自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的

 

 5. __call__ 对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo:
 
    def __init__(self):
        pass
     
    def __call__(self, *args, **kwargs):
 
        print '__call__'
 
 
obj = Foo() # 执行 __init__
obj()       # 执行 __call__

  

 


RESTRIAN_TIME = 1*60 #
LOOP_INVTIME = 3 #3秒执行一次
WTIMES = 6 # 执行6次
class time_restrian(object):
    def __init__(self,task_id):
        self.task_id = task_id
        self.first_timer = int(time.time())

    def __call__(self):
        now_time = int(time.time()) - self.first_timer
        abs_time = now_time % (LOOP_INVTIME*WTIMES+RESTRIAN_TIME)
        if LOOP_INVTIME*WTIMES < abs_time :
            return 1
        else:
            return 0

# 模拟告警
if __name__ == '__main__':
    i=1
    while True:
        i+=1
        try:
            if i==7:  # 开始
                named = 'uid'
                named = time_restrian('uid')
                print "diyici"
            elif i==17: # 恢复
                del named
                print "huifu"
            else:  # 一直在告警
                print named(),"gaojing"
            time.sleep(1)  # 1s一次
        except Exception,e:
            pass
>>
diyici
gaojing
gaojing
gaojing
gaojing
gaojing
gaojing
gaojing
gaojing
gaojing
huifu

使用__call__实现时间抑制
使用__call__实现时间抑制

  

6. __dict__ 查看类或对象中的所有成员    

class Province:
 
    country = 'China'
 
    def __init__(self, name, count):
        self.name = name
        self.count = count
 
    def func(self, *args, **kwargs):
        print 'func'
 
# 获取类的成员,即:静态字段、方法、
print Province.__dict__
# 输出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}
 
obj1 = Province('HeBei',10000)
print obj1.__dict__
# 获取 对象obj1 的成员
# 输出:{'count': 10000, 'name': 'HeBei'}
 
obj2 = Province('HeNan', 3888)
print obj2.__dict__
# 获取 对象obj1 的成员
# 输出:{'count': 3888, 'name': 'HeNan'}

__dict__

  

7.__getattr__ 

如果属性查找(attribute lookup)在实例以及对应的类中(通过__dict__)失败, 那么会调用到类的__getattr__函数, 如果没有定义这个函数,那么抛出AttributeError异常。由此可见,__getattr__一定是作用于属性查找的最后一步,兜底。

第一个例子,很简单但很经典,可以像访问属性一样访问dict中的键值对
class ObjectDict(dict):
    def __init__(self, *args, **kwargs):
        super(ObjectDict, self).__init__(*args, **kwargs)

    def __getattr__(self, name):
        value =  self[name]
        if isinstance(value, dict):
            value = ObjectDict(value)
        return value

if __name__ == '__main__':
    od = ObjectDict(asf={'a': 1,'b':{'d':0}}, d=True)
    print od.asf, od.asf.a     # {'a': 1, 'b': {'d': 0}} 1
    print od.asf.b.d           # 0
    print od.d                 # True
第二个例子,对象属性的lazy intialize,延迟加载
class WidgetShowLazyLoad(object):
    def fetch_complex_attr(self, attrname):
        '''可能是比较耗时的操作, 比如从文件读取'''
        time.sleep(3)
        print "====> cost 3s"
        return attrname

    def __getattr__(self, name):
        # if name not in self.__dict__:
        if name == "lazy_loaded_attr":
             self.__dict__[name] = self.fetch_complex_attr(name) 
        return self.__dict__[name]

if __name__ == '__main__':
    w = WidgetShowLazyLoad()
    print 'before', w.__dict__
    w.lazy_loaded_attr
    print 'after', w.__dict__

  输出:

before {}
====> cost 3s
after {'lazy_loaded_attr': 'lazy_loaded_attr'}

可以看到,属性访问前对象中的__dict__没有任何元素,访问之后就有添加。
这个例子是类实例的属性的惰性初始化,bottle里面也有一个用descriptor实现类属性的惰性初始化。
import functools
class lazy_attribute(object):
    """ A property that caches itself to the class object. """

    def __init__(self, func):
        functools.update_wrapper(self, func, updated=[])
        self.getter = func

    def __get__(self, obj, cls):
        value = self.getter(cls)
        setattr(cls, self.__name__, value)
        return value

class Widget(object):
    @lazy_attribute
    def complex_attr_may_not_need(clz):
        print 'complex_attr_may_not_need is needed now'
        return sum(i*i for i in range(1000))

if __name__ == '__main__':
    print Widget.__dict__.get('complex_attr_may_not_need')  # <__main__.lazy_attribute object at 0x02B12450>
    Widget.complex_attr_may_not_need                        # complex_attr_may_not_need is needed now
    print Widget.__dict__.get('complex_attr_may_not_need')  # 332833500

  

第三个例子,也是最实用的,__getattr__实现adapter wrapper模式,我们都知道"组合优于继承",__getattr__实现的adapter就是以组合的形式来扩展类的方法,但又不是继承
class adaptee(object):
    def foo(self):
        print 'foo in adaptee'
    def bar(self):
        print 'bar in adaptee'
    def biz(self):
        print 'biz in adaptee'

class adapter(object):
    def __init__(self):
        self.adaptee = adaptee()

    def foo(self):
        print 'foo in adapter'
        self.adaptee.foo()

    def bar(self):
        print 'bar in adapter'

    def __getattr__(self, name):
        return getattr(self.adaptee, name)

if __name__ == '__main__':
    a = adapter()
    a.foo()
    a.biz()
    a.bar()  # 第一选择仍然是本身self.__dict__中的方法,本身没有才会找__getattr__方法

如果adapter需要修改adaptee 的行为,那么定义一个同名的属性就可以了,其他的直接"继承"adaptee的属性,通通交给__getattr__就可以了  

最后一个例子,实际使用中的例子:  
class AlgoImpA(object):
    def __init__(self):
        self.obj_attr = 'obj_attr in AlgoImpA'

    def foo(self):
        print 'foo in AlgoImpA'

    def bar(self):
        print 'bar in AlgoImpA'

class AlgoImpB(object):
    def __init__(self):
        self.obj_attr = 'obj_attr in AlgoImpB'

    def foo(self):
        print 'foo in AlgoImpB'

    def bar(self):
        print 'bar in AlgoImpB'

class Algo(object):
    def __init__(self):
        self.imp_a = AlgoImpA()
        self.imp_b = AlgoImpB()
        self.cur_imp = self.imp_a

    def switch_imp(self):
        if self.cur_imp == self.imp_a:
            self.cur_imp = self.imp_b
        else:
            self.cur_imp = self.imp_a

    def __str__(self):
        return 'Algo with imp %s' % str(self.cur_imp)


    def __getattr__(self, name):
        return getattr(self.cur_imp, name)


if __name__ == '__main__':
    algo = Algo()
    
    print algo
    print algo.obj_attr
    algo.foo()
    
    algo.switch_imp()   # 切换不同的"继承"源
    
    print algo
    print algo.obj_attr
    algo.bar()

  输出:

Algo with imp <__main__.AlgoImpA object at 0x7f7699ac7650>
obj_attr in AlgoImpA
foo in AlgoImpA

<切换"继承">
Algo with imp <__main__.AlgoImpB object at 0x7f7698165750>
obj_attr in AlgoImpB
bar in AlgoImpB

 首先,Algo提供给使用者的接口应该尽量简单,因此应该使用algo.foo, 而不是algo.cur_imp.foo. 其次,AlgoImpA和AlgoImpB都有很多属性,使用__getattr__能大幅简化代码

 

8.__str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

 

class Foo:
 
    def __str__(self):
        return 'alex li'
 
 
obj = Foo()
print obj
# 输出:alex li

__str__

  

9.__getitem__、__setitem__、__delitem__

用于索引操作,如字典。以上分别表示获取、设置、删除数据

class Foo(object):
 
    def __getitem__(self, key):
        print('__getitem__',key)
 
    def __setitem__(self, key, value):
        print('__setitem__',key,value)
 
    def __delitem__(self, key):
        print('__delitem__',key)
 
 
obj = Foo()
 
result = obj['k1']      # 自动触发执行 __getitem__
obj['k2'] = 'alex'   # 自动触发执行 __setitem__
del obj['k1']   

view code

   

10. __new__ \ __metaclass__

class Foo(object):
 
    def __init__(self,name):
        self.name = name
 
 
f = Foo("gaotao")

  

上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象

如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

print type(f) # 输出:<class '__main__.Foo'>     表示,obj 对象由Foo类创建
print type(Foo) # 输出:<type 'type'>              表示,Foo类对象由 type 类创建

所以,f对象是Foo类的一个实例Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。

那么,创建类就可以有两种方式:

a). 普通方式 

class Foo(object):
  
    def func(self):
        print 'hello alex'

 

b). 特殊方式

def func(self):
    print 'hello wupeiqi'
  
Foo = type('Foo',(object,), {'func': func})
#type第一个参数:类名
#type第二个参数:当前类的基类
#type第三个参数:类的成员

 

def func(self):
    print("hello %s"%self.name)

def __init__(self,name,age):
    self.name = name
    self.age = age
Foo = type('Foo',(object,),{'func':func,'__init__':__init__})

f = Foo("jack",22)
f.func()

 

魔术方法

类 是由 type 类实例化产生

那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。

 

 

class MyType(type):
    def __init__(self,*args,**kwargs):

        print("Mytype __init__",*args,**kwargs)

    def __call__(self, *args, **kwargs):
        print("Mytype __call__", *args, **kwargs)
        obj = self.__new__(self)
        print("obj ",obj,*args, **kwargs)
        print(self)
        self.__init__(obj,*args, **kwargs)
        return obj

    def __new__(cls, *args, **kwargs):
        print("Mytype __new__",*args,**kwargs)
        return type.__new__(cls, *args, **kwargs)

print('here...')
class Foo(object,metaclass=MyType):


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

        print("Foo __init__")

    def __new__(cls, *args, **kwargs):
        print("Foo __new__",cls, *args, **kwargs)
        return object.__new__(cls)

f = Foo("Alex")
print("f",f)
print("fname",f.name)
自定义元类

 

 

 类的生成 调用 顺序依次是 __new__ --> __init__ --> __call__

 metaclass 详解文章:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 得票最高那个答案写的非常好

 

反射

通过字符串映射或修改程序运行时的状态、属性、方法, 有以下4个方法

getattr(object,name)

def getattr(object, name, default=None): # known special case of getattr
    """
    getattr(object, name[, default]) -> value
    
    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn't
    exist; without it, an exception is raised in that case.
    """
    pass

getattr(object, name, default=None)

 

hasattr(object,name)

if hasattr(d,choice):
    func = getattr(d,choice) #根据字符串获取obj对象,输入eat后就调用了Dog.eat()
    func("baozi")

setattr(x, y, z)

def setattr(x, y, v): # real signature unknown; restored from __doc__
    """
    Sets the named attribute on the given object to the specified value.
    
    setattr(x, 'y', v) is equivalent to ``x.y = v''

 

delattr(x, y)

def delattr(x, y): # real signature unknown; restored from __doc__
    """
    Deletes the named attribute from the given object.
    
    delattr(x, 'y') is equivalent to ``del x.y''
    """

delattr(x, y)

 

反射举例

#!/usr/bin/env python
# set coding: utf-8
__author__ = "richardzgt"


class Dog(object):
    def __init__(self,name):
        self.name = name
        print("staring %s" % self.name)
    def eat(self,args):
        self.args = args
        print("eat %s.."% self.args )

def newskill(self,skill):
    print("%s add new skill %s" % (self.name,skill))

d = Dog('jj')
# d.eat('baozi')
choice = input('>>:') # 输入eat
print(choice)
if hasattr(d,choice):
    func = getattr(d,choice) #根据字符串获取obj对象,输入eat后就调用了Dog.eat()
    func("baozi")

else:
    setattr(d,choice,newskill)

    # d.cat(d,'gaotao')
    v_method = getattr(d,choice)
    # d.v_method(d,'gaotao')
    v_method(d,'fuck')

结果输出  

staring jj
>>:eat
eat
eat baozi..

staring jj
>>:hahd
hahd
jj add new skill fuck

   

动态导入模块

 

 

import importlib
 
__import__('import_lib.metaclass') #这是解释器自己内部用的
#importlib.import_module('import_lib.metaclass') #与上面这句效果一样,官方建议用这个

 

 

异常处理 

1 异常种类

AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
常用异常

 

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
更多异常

 

 

Exception 所有异常的基类
AttributeError  特性应用或赋值失败时引发
IOError 试图打开不存在的文件时引发
IndexError 在使用序列中不存在的索引时引发
KeyError 在使用映射不存在的键时引发
NameError 在找不到名字(变量)时引发
SyntaxError

在代码为错误形式时引发

TypeError 在内建操作或者函数应用于错误类型的对象是引发
ValueError 传入无效的参数
ZeroDivisionError 在除法或者摸除操作的第二个参数为0时引发
EOFError

一般是读到了空文件的时候,才会引发

ImportError 导入模块/对象失败
KeyboardInterrupt 用户中断执行
UnboundLocalErrorh 访问未初始化的本地变量
IndentationError  缩进错误
UnicodeError Unicode 相关的错误
   
   

dic = ["wupeiqi", 'alex']
try:
    dic[10]
except IndexError, e:
    print e
IndexError
dic = {'k1':'v1'}
try:
    dic['k20']
except KeyError, e:
    print e
KeyError

 

s1 = 'hello'
try:
    int(s1)
except ValueError, e:
    print e
ValueError

except socket.gaierror:
    print( 'Hostname could not be resolved. Exiting')
    sys.exit()

except socket.error:
    print( "Couldn't connect to server")
    sys.exit()
socketError

 

except KeyboardInterrupt:
    print( "You pressed Ctrl+C")
    sys.exit()
KeyboardInterrupt

 




对于上述实例,异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。
s1 = 'hello'
try:
    int(s1)
except KeyError,e:
    print '键错误'
except IndexError,e:
    print '索引错误'
except Exception, e:
    print '错误'

 

2、异常其他结构 

try:
    # 主代码块
    s = 10
    return s
except KeyError,e:
    # 出现keyError异常时,执行该块
    pass
except Exception as e:
    # 所有异常都会在此捕获
    s = 1
    return s
else:
    # 主代码块执行成功,执行该块
    pass
finally:
    # 无论异常与否,最终执行该块
    return 100

注意 凡是最后有finally statement的return ,都会优先执行return或者break out

  

 

3、主动触发异常

try:
    raise Exception('错误了。。。')
except Exception,e:
    print e

 

在以下例子中可以看到,如果raise出现在exception里面,请带上 from e (py3下),这样可以捕获全部异常后抛出另外的自定义的异常

class ServerError(Exception):
    pass

try:    
    int('dss')
except Exception as e:
    raise ServerError("ttttttt") from e


>>>>>>>>>>
Traceback (most recent call last):
  File "test3.py", line 20, in <module>
    int('dss')
ValueError: invalid literal for int() with base 10: 'dss'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "test3.py", line 22, in <module>
    raise ServerError("ttttttt") from e
__main__.ServerError: ttttttt  

 

4、自定义异常

class myexception(Exception):
    # def __init__(self, msg):  # 不写,直接pass也可以
    #     self.message = msg
    pass

try:
    raise myexception("ff")

except Exception as e:
    print(e)
    pass

 

 

5、对象中捕获异常

class ZbxServerError(Exception):
    """获取异常后 发送告警邮件"""
    def __init__(self,ErrorInfo): 
        super(ZbxServerError,self).__init__()
        self.errorinfo=ErrorInfo
        m = sendMail.Mail(u"[CRITICAL]zabbix server down!!!")
        m.Content(self.errorinfo)
        m.TO_user("gaotao@huored.com")
        m.sendmail_ssl()  # 发送邮件

    def __str__(self):
        return self.errorinfo


class zbx_check(zbx_api): # 继承父类
    def __init__(self,*args):
        try:
            super(zbx_check,self).__init__(*args)  # 把参数送给父类 
        except Exception as e:
            raise ZbxServerError("zabbix master can't connect !") # 捕获父类中__init__ 的异常,并触发异常处理

z = zbx_check(url,user,pwd)

  

6、断言assert自定义异常

try:    
    assert status == 0, "exec_cmd:[%s] failed! recive exit[%s]" % (each_cmd,status)  // 定义断言内容
except (AssertionError,Exception),e:
    print(str(e))
else:
    print("exec successful[%s]" % host)

 

 

 




 









posted @ 2017-11-03 15:09  richardzgt  阅读(321)  评论(0编辑  收藏  举报