Python基础-week06 面向对象编程进阶

一.反射

  1.定义:指的是经过字符串来操做类或者对象的属性python

  2.为何用反射?git

    减小冗余代码,提高代码质量。安全

  3.如何用反射?框架

    

class People:
    country='China'
    def __init__(self,name):
        self.name=name


obj=People('jame')


#hasattr
#print('country' in People.__dict__)
print(hasattr(People,'country'))

#getattr
#print(People.__dict__['country'])
#print(getattr(People,'country)) #若是取不到值,会报错。
print(getattr(People,'country',None)) #None若是取不到值不报错,返回None


#setattr
#obj.age=18
#print(obj.__dict__)
setattr(obj,'age',18)
print(obj.__dict__) #{'name': 'jame', 'age': 18}
setattr(People,'x',111)
print(People.__dict__)
#{......, '__doc__': None, 'x': 111}


#delattr
delattr(People,'x')
print(People.__dict__)
#{......, '__doc__': None}
例1:反射涉及的4个内置函数
class Ftp:
    def get(self):
        print('get...')


    def put(self):
        print('put...')


    def auth(self):
        print('auth...')



    def run(self):
        while True:
            cmd=input('Please input:').strip() #cmd='get
            if hasattr(self,cmd):
                method=getattr(self,cmd)
                method()

            else:
                print('You please input error')



obj=Ftp()
obj.run()
例2:反射的简单使用

 

  动态导入模块<了解>:ide

  

   

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

 

  

二.一些内置方法 和 内置函数介绍

  1.isinstance(obj,cls)和issubclass(sub,super)

    isinstance(obj,cls)检查是否obj是不是类 cls 的对象。函数

    issubclass(sub,super) 检查sub类是不是 super类的派生类。    工具

class Foo(object):
    pass


class bar(Foo):
    pass



obj=Foo()

#1 isinstance判断对象是否属于某类
res1=isinstance(obj,Foo)
print(res1) #True

#2 issubclass 判断bar类是不是 Foo 类的派生类
res2=issubclass(bar,Foo)
print(res2) #true
View Code

 

  2.__setattr__ ,__delattr__ ,__getattr__测试

   配合反射机制使用,效果还不错. spa

class People:
    country='China'
    def __init__(self,name):
        self.name=name


obj=People('jame')


#hasattr
#print('country' in People.__dict__)
print(hasattr(People,'country'))

#getattr
#print(People.__dict__['country'])
#print(getattr(People,'country123')) #若是取不到值,会报错。AttributeError: type object 'People' has no attribute 'country123'
print(getattr(People,'country123',None)) #None若是取不到值不报错,返回None


#setattr
#obj.age=18
#print(obj.__dict__)
setattr(obj,'age',18)
print(obj.__dict__) #{'name': 'jame', 'age': 18}
setattr(People,'x',111)
print(People.__dict__)
#{......, '__doc__': None, 'x': 111}


#delattr
delattr(People,'x')
print(People.__dict__)
#{......, '__doc__': None}
在类外部使用实例 
class Foo:
    x=1

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


    def __getattr__(self, item):
        print('from getattr:你找的属性不存在.')



    def __setattr__(self, key, value):
        print('from setattr')
        
        

    def __delattr__(self, item):
        print('from delattr')
        self.__dict__.pop(item)



#1 __setattr__ 添加、修改属性会触发它的执行
f1=Foo(10) #from setattr
print(f1.__dict__) #{}
#由于你重写了__setattr__,凡是赋值操做都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操做属性字典,不然永远没法赋值
f1.__dict__['a']=3
f1.__dict__['b']=4
print(f1.__dict__) #{'a': 3, 'b': 4}




#2 __deattr__ 删除属性的时候会触发
#f1.__dict__['a']=10 #咱们能够经过修改属性字典,来完成添加、修改属性的操做
del f1.a #from delattr
print(f1.__dict__) #{'b':4}还剩b



# 3 __getattr__ 只有使用点调用属性且属性不存在的时候才会触发
f1.abc #from getattr:你找的属性不存在.
View Code
class Ftp:
    def get(self):
        print('get...')


    def put(self):
        print('put...')


    def auth(self):
        print('auth...')



    def run(self):
        while True:
            cmd=input('Please input:').strip() #cmd='get
            if hasattr(self,cmd):
                method=getattr(self,cmd)
                method()

            else:
                print('You please input error')



obj=Ftp()
obj.run()
配合反射使用实例

 

   3.__getattribute__3d

    

# @Time    : 2018/8/20 17:19
# @Author  : Jame
# class Foo:
#     def __init__(self,x):
#         self.x=x
#
#     def __getattr__(self, item):
#         print('执行的是__getattr__')
#
#
#
#
# f1=Foo(100)
# print(f1.x)
# f1.xxx #若访问的不存在,则 “执行的是__getattr__”


class Foo:
    def __init__(self,x):
        self.x=x

    def __getattribute__(self, item):
        print('不论是否存在都执行的是__getattribute__')


f1=Foo(200)
f1.x
f1.xxx
getattr与getattribute的使用
class Foo:
    def __init__(self,x):
        self.x=x

    def __getattr__(self, item):
        print('若是不存在则执行__getattr__')

    def __getattribute__(self, item):
        print('不论是否存在都执行的是__getattribute__')
        raise AttributeError('哈哈 嘿嘿 哟哟')


f1=Foo(200)
f1.x
f1.xxx
getattr和getattribute同时存在实例
#当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程当中抛出异常AttributeError

 

  4.描述符(__get__ , __set__, __delete__)

    (1).1 描述符是什么?

      描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
      __get__():调用一个属性时,触发
      __set__():为一个属性赋值时,触发
      __delete__():采用del删除属性时,触发

   

#1 定义一个描述符
class Foo:
    def __get__(self, instance, owner):
        print('__get__')

    def __set__(self, instance, value):
        print('__set__')

    def __delete__(self, instance):
        print('__delete__')
定义一个描述符

 

 

    (2).描述符是干什么的,什么时候触发描述符中的3个方法呢?

      描述符的做用是用来代理另一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中__init__())

      包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法!例如:

      

#2 描述符的使用
class Foo2:
    def __get__(self, instance, owner):
        print('触发 __get__')

    def __set__(self, instance, value):
        print('触发 __set__')

    def __delete__(self, instance):
        print('触发 __delete__')


#包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法!
f2=Foo2()
f2.name='jame'
print(f2.name)
del f2.name
描述符的实例进行调用/赋值/删除不会触发

       

      #何地?:定义成另一个类的类属性

      #什么时候?:且看下列演示
class Str:
    def __get__(self, instance, owner):
        print('Str 调用')

    def __set__(self, instance, value):
        print('str 设置')

    def __delete__(self, instance):
        print('str 删除')


class Int:
    def __get__(self, instance, owner):
        print('Int 调用')

    def __set__(self, instance, value):
        print('Int 设置')

    def __delete__(self, instance):
        print('Int 删除')


class People:
    name=Str()
    age=Int()

    def __init__(self,name,age): #name 被设置为Str类的的代理,age被设置Int类的代理。
        self.name=name
        self.age=age


#何地?:定义成另一个类的类属性

#什么时候?:且看下列演示

p1=People('jame',18) #触发Str 设置,Int 设置!


#1 描述符str的使用 调用,设置,删除
#p1.name
#p1.name='tom'
#del p1.name
'''
Str 调用
str 设置
str 删除
'''

#2 描述符int的使用  调用,设置,删除
#p1.age
#p1.age=30
#del p1.age
'''
Int 调用
Int 设置
Int 删除
'''


#3 咱们来瞅瞅到底发生了什么?
print(p1.__dict__)
print(People.__dict__)


#补充
print(type(p1) == People) #True,type(p1) 查看p1是哪一个类实例化来的。
print(type(p1).__dict__==People.__dict__) #True
触发描述符的场景

 

    (3).描述符分两种

      1).数据描述符:至少实现了__get__()和__set__()      

1 class Foo:
2     def __set__(self, instance, value):
3         print('set')
4     def __get__(self, instance, owner):
5         print('get')

 

      2).非数据描述符:没有实现__set__()

  

class Foo:
2     def __get__(self, instance, owner):
3         print('get')

 

    (4).注意事项:
    一 描述符自己应该定义成新式类,被代理的类也应该是新式类
    二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
    三 要严格遵循该优先级,优先级由高到底分别是
      1.类属性
      2.数据描述符
      3.实例属性
      4.非数据描述符
      5.找不到的属性触发__getattr__()

      

#描述符str

class Str:
    def __get__(self, instance, owner):
        print('str 调用')


    def __set__(self, instance, value):
        print('Str 设置')


    def __delete__(self, instance):
        print('Str 删除')



class People:
    name=Str()

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



People.name #调用类属性name,本质就是在调用描述符Str,触发了__get__()

People.name='egon' #赋值并无触发__set__()的设置


del People.name #删除也并无触发 __del__() 的设置


#结论:描述符对类没有做用-------->傻逼到家的结论
'''

缘由:描述符在使用时被定义成另一个类的类属性,于是类属性比二次加工的描述符假装而来的类属性有更高的优先级
People.name #恩,调用类属性name,找不到就去找描述符假装的类属性name,触发了__get__()

People.name='egon' #那赋值呢,直接赋值了一个类属性,它拥有更高的优先级,至关于覆盖了描述符,确定不会触发描述符的__set__()
del People.name #同上

'''
类属性>数据描述符

 

#描述符Str
class Str:
    def __get__(self, instance, owner):
        print('Str调用')
    def __set__(self, instance, value):
        print('Str设置...')
    def __delete__(self, instance):
        print('Str删除...')


class People:
    name=Str()
    def __init__(self,name,age): #name被Str类代理,age被Int类代理,
        self.name=name
        self.age=age


p1=People('egon',18) #str设置,触发!

#若是描述符是一个数据描述符(即有__get__又有__set__),那么p1.name的调用与赋值都是触发描述符的操做,于p1自己无关了,至关于覆盖了实例的属性
p1.name='egonnnnnn' #str设置,触发!

p1.name #str调用,触发!

print(p1.__dict__) #实例的属性字典中没有name,由于name是一个数据描述符,优先级高于实例属性,查看/赋值/删除都是跟描述符有关,与实例无关了
del p1.name #str删除,触发!

###数据描述符>实例属性
数据描述符>实例描述符

 

class Foo:
    def func(self):
        print('我胡汉三又回来了')


f1=Foo()
f1.func()
#调用类的方法,也能够说是调用非数据描述符
#函数是一个非数据描述符对象(一切皆对象么)


print(dir(Foo.func))

print(hasattr(Foo.func,'__set__')) #False

print(hasattr(Foo.func,'__get__')) #True

print(hasattr(Foo.func,'__del__')) #False
#也有人可能问,描述符不都是类吗,函数怎么算也应该是一个对象,怎么就是描述符了。
#描述符是类没问题,描述符在应用的时候不都是实例化成一个类属性么
#函数就是有一个非描述符类实例化获得的一个对象
#没错,字符串也是同样



f1.func='这是实例属性啊'

print(f1.func)


del f1.func #删除了非数据
f1.func()   #我胡汉三又回来了
实例属性>非数据描述符

 

class Foo:
    def __set__(self, instance, value):
        print('foo set')

    def __get__(self, instance, owner):
        print('foo get')




class Room:
    name=Foo()
    def __init__(self,name,width,length):
        self.name=name
        self.width=width
        self.length=length



#name 是一个数据描述符,由于Name=Foo() 而Foo实现了get 和set方法,所以比实例属性有更高的优先级
#对实例的属性操做,触发的都是描述符
# r1=Room('厕所',1,1) #触发foo set
#
# r1.name            #触发foo get
#
# r1.name='厨房'     #触发 foo set



class Foo1:
    def __get__(self, instance, owner):
        print('Foo1 get')


class Room1:
    name=Foo1()

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

#name 是一个非数据描述符,由于name=Foo1() 可是Foo1中没有实现set方法,于是比实例属性的优先级更低
#对实例的属性操做,触发的都是实例本身
r2=Room1('大厦',100,100)
r2.name
r2.name='高塔'
再次验证:实例属性>非数据描述符

 

# @Time    : 2018/8/24 14:56
# @Author  : Jame
class Foo:
    def func(self):
        print('我胡汉三回来了')


    def __getattr__(self, item):
        print('找不到了固然是来找我啦',item)



f1=Foo()


f1.xxxx #找不到了固然是来找我啦 xxxx
非数据描述符>找不到

 

 

    (5).描述符的使用

    众所周知,python是弱类型语言,即参数的复制没有任何类型限制,下面咱们经过描述符机制来实现类型的功能。

    

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


    def __get__(self, instance, owner):
        print('--get-->',instance,owner)
        return instance.__dict__[self.name]


    def __set__(self, instance, value):
        print('---set--->',instance,value)
        instance.__dict__[self.name]=value

    def __delete__(self, instance):
        print('---del---',instance)
        instance.__dict__.pop(self.name)



class People:
    name=Str('name')
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary


p1=People('egon',18,3232.3) #Str---get---> <__main__.People object at 0x0000000002866630> egon

#1 调用
print(p1.__dict__) #{'name': 'egon', 'age': 18, 'salary': 3232.3}
p1.name #Str--get--> <__main__.People object at 0x00000000024F6630> <class '__main__.People'>


#2 赋值
print(p1.__dict__) #{'name': 'egon', 'age': 18, 'salary': 3232.3}
p1.name='jame-mei' #---set---> <__main__.People object at 0x00000000024E6668> jame-mei
print(p1.__dict__) #{'name': 'jame-mei', 'age': 18, 'salary': 3232.3}


#3 删除
print(p1.__dict__) #{'name': 'jame-mei', 'age': 18, 'salary': 3232.3}
del p1.name        #---del--- <__main__.People object at 0x0000000002566668>
print(p1.__dict__) #{'age': 18, 'salary': 3232.3}
1 小试菜刀

 

# @Time    : 2018/8/24 15:12
# @Author  : Jame
# class Str:
#     def __init__(self,name):
#         self.name=name
#
#
#     def __get__(self, instance, owner):
#         print('get--->',instance,owner)
#         return instance.__dic__[self.name]
#
#
#     def __set__(self, instance, value):
#         print('set--->',instance,value)
#         instance.__dic__[self.name]=value
#
#     def __delete__(self, instance):
#         print('delete--->',instance)
#         instance.__dic__.pop(self.name)
#
#
# class People:
#     name=Str('name')
#     def __init__(self,name,age,salary):
#         self.name=name
#         self.age=age
#         self.salary=salary

#疑问,若是我用类名去操做属性呢
#People.name  #报错,在于把类去操做属性,会把None传给instance


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


    def __get__(self, instance, owner):
        print('get--->',instance,owner)
        if instance is None:
            return self

        return instance.__dic__[self.name]


    def __set__(self, instance, value):
        print('set--->',instance,value)
        instance.__dic__[self.name]=value

    def __delete__(self, instance):
        print('delete--->',instance)
        instance.__dic__.pop(self.name)


class People:
    name=Str('name')
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary



People.name    #get---> None <class '__main__.People'>  解决
2 拔吊相助

 

class Str:
    def __init__(self,name,expected_type):
        self.name=name
        self.expected_type=expected_type

    def __get__(self, instance, owner):
        print('get--->',instance,owner)
        if instance is None:
            return self
        return  instance.__dict__[self.name]


    def __set__(self, instance, value):
        print('set--->',instance,value)
        if not instance(value,self.expected_type):
            raise TypeError('Expected %s'%str(self.expected_type))

        instance.__dict__[self.name]=value

    def __delete__(self, instance):
        print('delete--->',instance)
        instance.__dict__.pop(self.name)



class People:
    name=Str('name',str) #新增类型限制str
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary


p1=People(123,18,333.3) #传入的name 因不是字符串类型而抛出异常
#TypeError: 'People' object is not callable
3 磨刀霍霍

 

class Typed:
    def __init__(self,name,expected_type):
        self.name=name
        self.expected_type=expected_type

    def __get__(self, instance, owner):
        print('get--->',instance,owner)
        if instance is None:
            return self

        return instance.__dict__[self.name]


    def __set__(self, instance, value):
        print('set--->',instance,value)
        if not isinstance(value,self.expected_type):
            raise TypeError('Expected %s'%str(self.expected_type))
        instance.__dict__[self.name]=value


    def __delete__(self, instance):
        print('delete--->',instance)
        instance.__dict__.pop(self.name)


class People:
    name=Typed('name',str)
    age=Typed('name',int)
    salary=Typed('name',float)
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary



#p1=People(123,18,33.33) #set---> <__main__.People object at 0x0000000002896780> 123
#TypeError: Expected <class 'str'>

#p2=People('tom','18',33.33) #set---> <__main__.People object at 0x00000000028967F0> tom
#TypeError: Expected <class 'int'>

p3=People('jame',18,33.33)
#set---> <__main__.People object at 0x00000000024A67B8> jame
#set---> <__main__.People object at 0x00000000024A67B8> 18
#set---> <__main__.People object at 0x00000000024A67B8> 33.33
4 大刀阔斧

 

  通过上述几个例子虽然能逐步实现了功能,可是问题是咱们的类有不少属性的时候,仍然采用定义一堆属性的方式去实现,比较low,因此须要经过装饰器来实现:

def decorate(cls):
    print('类的装饰器开始运行啦...')
    return cls


@decorate
class People1:
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary



p1=People1('jame',18,33.33) #类的装饰器开始运行啦...



def typeassert(**kwargs):
    def decorate(cls):
        print('类的装饰器开始运行啦----',kwargs)
        return cls

    return decorate


@typeassert(name=str,age=int,salary=float)
class People2:
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary


p2=People2('jame',18,23.3)
#类的装饰器开始运行啦---- {'name': <class 'str'>, 'age': <class 'int'>, 'salary': <class 'float'>}
5 无参和有参的类的装饰器

 

   

class Typed:
    def __init__(self,name,expected_type):
        self.name=name
        self.expected_type=expected_type


    def __get__(self, instance, owner):
        print('get--->',instance,owner)
        if instance is None:
            return self

        return instance.__dict__[self.name]


    def __set__(self, instance, value):
        print('set--->',instance,value)
        if not isinstance(value,self.expected_type):
            raise TypeError('Expected %s'%str(self.expected_type))

        instance.__dict__[self.name]=value

    def __delete__(self, instance):
        print('delete--->',instance)
        instance.__dict__.pop(self.name)




def typeassert(**kwargs):
    def decorate(cls):
        print('类的装饰器开始运行啦---->',kwargs)
        for name,expected_type in kwargs.items():
            setattr(cls,name,Typed(name,expected_type))

        return cls
    return decorate


@typeassert(name=str,age=int,salary=float)
class People:
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary


print(People.__dict__)
p1=People('jame',18,28888.8)
#set---> <__main__.People object at 0x00000000028C6860> jame
#set---> <__main__.People object at 0x00000000028C6860> 18
#set---> <__main__.People object at 0x00000000028C6860> 28888.8
6 终极葵花宝典

 

    (6).描述符总结

      描述符是能够实现大部分Python类特性中的底层魔法,包括@classmethod ,@staticmethod,@property 甚至是__slots__属性的

      描述符是不少高级哭和框架的重要工具之一,描述符一般是使用到装饰器或者元类的大型框架中的一个组件。

 

    (7).用描述符原理完成一个自定制@property,实现延迟计算.

      (本质就是把一个函数属性利用装饰器原理 作成一个描述符:类的类型字典中函数名为key,valued为描述符类产生的 对象)

class Room:
    def __init__(self,name,width,length):
        self.name=name
        self.width=width
        self.length=length


    @property #能够把一个函数看成属性来使用!
    def area(self):
        return self.width*self.length



r1=Room('jame',3,4)
print(r1.area)
1 回顾property

 

class Lazyproperty:
    def __init__(self,func):
        self.func=func

    def __get__(self, instance, owner):
        print('这是咱们本身定制的静态属性, r1.area实际是要执行r1.area()')
        if instance is None:
            return self
        return self.func(instance) ##此时你应该明白,究竟是谁在为你作自动传递self的事情



class Room:
    def __init__(self,name,width,length):
        self.name=name
        self.width=width
        self.length=length


    @Lazyproperty
    def area(self):
        return self.width*self.length



r1=Room('tom',3,4)
print(r1.area)
#这是咱们本身定制的静态属性, r1.area实际是要执行r1.area()
#12
2 本身定义一个@property

 

class Lazyproperty:
    def __init__(self,func):
        self.func=func

    def __get__(self, instance, owner):
        print('这是咱们本身定制的静态属性,r1.area实际是要执行r1.area()')
        if instance is None:
            return self
        else:
            print('----->')
            value=self.func(instance)
            setattr(instance,self.func.__name__,value)




class Room:
    def __init__(self,name,width,length):
        self.name=name
        self.width=width
        self.length=length

    @Lazyproperty #area=Lazyproperty(area)
    def area(self):
        return self.width*self.length



r1=Room('tom',3,4)
print(r1.area) #先从本身的属性字典找,没有再去类的中找,而后出发了area的__get__方法
print(r1.area) #先从本身的属性字典找,找到了,是上次计算的结果,这样就不用每执行一次都去计算
3 实现延迟计算功能

 

 

 

    (8).用描述符原理完成一个自定制  @classmethod

       

class ClassMethod:
    def __init__(self,func):
        self.func=func


    def __get__(self, instance, owner):#类来调用,instance为None,owner为类自己,实例用来调用,instance为实例,owner为类自己
        def feedback():
            print('在这里能够加功能...')
            return self.func(owner)

        return feedback


class People:
    name='jame'
    @ClassMethod #say_hi=ClassMethod(say_hi)
    def say_hi(cls):
        print('你好啊 ,帅哥 %s'%cls.name)


People.say_hi()
#在这里能够加功能...
#你好啊 ,帅哥 jame

p1=People()
p1.say_hi()
#在这里能够加功能...
#你好啊 ,帅哥 jame






#疑问:类方法若是有参数呢?
class ClassMethod2:
    def __init__(self,func):
        self.func=func

    def __get__(self, instance, owner):
        def feedback(*args,**kwargs):
            print('在这里能够加功能...')
            return self.func(owner,*args,**kwargs)

        return feedback


class People2:
    name='tom'
    @ClassMethod2  #say_hi=ClassMethod2(say_hi)
    def say_hi(cls,msg):
        print('你好啊,帅哥 %s %s'%(cls.name,msg))



People2.say_hi('你是那偷心的贼')


#p2=People2()
#p2.say_hi('你是哪偷心的贼')
只定义@classmethod

 

    (9).用描述符原理完成一个自定制 @staticmethod

    

class StaticMethod:
    def __init__(self,func):
        self.func=func

    def __get__(self, instance, owner):
        def feedback(*args,**kwargs):
            print('在这里能够加功能...')
            return self.func(*args,**kwargs)

        return feedback


class People:
    
    @StaticMethod  #say_hi=StaticMethod(say_hi)
    def say_hi(x,y,z):
        print('---->',x,y,z)



People.say_hi(1,2,3)

p1=People()
p1.say_hi(4,5,6)
本身作一个@staticmethod

 

 

  5.再看Property 

    一个静态属性property本质就是实现了get,set,delete三种方法

    

 

  6.__setitem__,__getitem,__delitem__

 

  7.__str__,__repr__,__format__

 

  8.__slots__

 

  9.__next__  和 __iter__ 实现迭代器的协议

 

  10.__doc__

 

  11.__module__ 和__class__

 

  12.__del__

 

  13.__enter__ 和 __exit__

 

  14.__call__

 

  15.metaclass

 

 

三.元类

  待更新...

 

 

四.异常处理

  1.什么是异常?

    异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止),在python中,错误触发的异常以下:

    

 

    而错误分红两种:

    

#语法错误示范一
if
#语法错误示范二
def test:
    pass
#语法错误示范三
class Foo
    pass
#语法错误示范四
print(haha
1.语法错误(这种错误,根本过不了python解释器的语法测试,必须在程序执行前就改为!)
#TypeError:int类型不可迭代
for i in 3:
    pass
#ValueError
num=input(">>: ") #输入hello
int(num)

#NameError
aaa

#IndexError
l=['egon','aa']
l[3]

#KeyError
dic={'name':'egon'}
dic['age']

#AttributeError
class Foo:pass
Foo.x

#ZeroDivisionError:没法完成计算
res1=1/0
res2=1+'str'

2.逻辑错误
2.逻辑错误

 

  2.异常的种类?

    在python中不一样的异常能够用不一样的类型(python 中统一了类与类型,类型便是类) 去标识,一个异常标识就是一种错误.

    

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

更多异常
更多异常

 

  3.异常处理

    为了保证程序的健壮性与容错性,即在遇到错误时程序不会崩溃,咱们须要对异常进行处理,

    若是错误发生的条件是可预知的,咱们须要用if进行处理:在错误发生以前进行预防

    

AGE=10
while True:
    age=input('>>: ').strip()
    if age.isdigit(): #只有在age为字符串形式的整数时,下列代码才不会出错,该条件是可预知的
        age=int(age)
        if age == AGE:
            print('you got it')
            break
if 提早预防方式处理

    

    若是错误发生的条件是不可预知的,则须要用到try...except:在错误发生以后进行处理

    

#基本语法为
try:
    被检测的代码块
except 异常类型:
    try中一旦检测到异常,就执行这个位置的逻辑
#举例
try:
    f=open('a.txt')
    g=(line.strip() for line in f)
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
except StopIteration:
    f.close()
try ...except方式处理
#1 异常类只能用来处理指定的异常状况,若是非指定异常则没法处理。
s1 = 'hello'
try:
    int(s1)
except IndexError as e: # 未捕获到异常,程序直接报错
    print e


#2 多分支
s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print(e)
except KeyError as e:
    print(e)
except ValueError as e:
    print(e)



#3 万能异常Exception
s1 = 'hello'
try:
    int(s1)
except Exception as e:
    print(e)



#4 多分支异常与万能异常

#4.1 若是你想要的效果是,不管出现什么异常,咱们统一丢弃,或者使用同一段代码逻辑去处理他们,那么骚年,大胆的去作吧,只有一个Exception就足够了。
#4.2 若是你想要的效果是,对于不一样的异常咱们须要定制不一样的处理逻辑,那就须要用到多分支了。




#5 也能够在多分支后来一个Exception
s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print(e)
except KeyError as e:
    print(e)
except ValueError as e:
    print(e)
except Exception as e:
    print(e)




#6 异常的其余机构
s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print(e)
except KeyError as e:
    print(e)
except ValueError as e:
    print(e)
#except Exception as e:
#    print(e)
else:
    print('try内代码块没有异常则执行我')
finally:
    print('不管异常与否,都会执行该模块,一般是进行清理工做')



#7 主动触发异常
try:
    raise TypeError('类型错误')
except Exception as e:
    print(e)

#8 自定义异常
class EgonException(BaseException):
    def __init__(self,msg):
        self.msg=msg
    def __str__(self):
        return self.msg

try:
    raise EgonException('类型错误')
except EgonException as e:
    print(e)

#9 断言:assert 条件
assert 1 == 1  
assert 1 == 2
try-except 多种应用实例

    

    #10 总结try..except

    1:把错误处理和真正的工做分开来
   2:代码更易组织,更清晰,复杂的工做任务更容易实现;
   3:毫无疑问,更安全了,不至于因为一些小的疏忽而使程序意外崩溃了;

 

  4.何时用异常处理?  

    Try--except是你附加给你的程序的一种异常处理的逻辑,与你的主要的工做是没有关系的,这种东西加太多会致使代码可读性变差,只有在错误发生的条件没法预知的状况下,才应该加上try ... except!

相关文章
相关标签/搜索