Python自动化运维 - day8 - 面向对象高级及异常处理

类的内置方法

既以__开头,以__结尾的方法,称之为内置方法

1、__str__
  用于类被实例化后,直接打印实例化对象时,显示的提示信息,注意,这里必须要用return

def __str__(self):
    return 'this is School object'

2、__init__
  用于初始化类的内部状态

def __init__(self,name,age):	-->可以添加参数
  self.name = name
  self.age = age	  --> 初始化的时候,自动赋值的属性
  self.talk()	    -->可以在初始化的时候,直接执行某些方法,用于在实例化的时候,自动执行

3、__del__
  析构函数 ,用于释放对象占用的资源,在脚本执行完毕后,自动进行资源释放(比如在构造函数中打开了某些文件,那么就可以在析构函数中关闭这些文件)

def __del__(self):
    print('bye bye')

4、__doc__
  表示描述信息,一般在class中进行定义

class People(object):
    'hello everyone'
    pass
ren = People()
print(People.__doc__)

5、__module__ 、__class__、__bases__

    • __module__ 表示当前操作的对象在哪个模块
    • __class__ 表示当前操作的对象的类是什么
    • __bases__ 表示当前类的父类是谁

6、__call__

  调用类/对象时,执行的方法。
    注意:
      类加括弧执行,其实就是执行的是 类的类(元类)的 __call__ 方法
      对象加括弧执行,其实执行的是类的 __call__ 方法

  callable()函数,可以判断一个对象是否是可调用的对象
  call函数也可以接受参数,和普通的函数功能相同

class People(object):
    'hello everyone'

    def __init__(self):
        print('init')

    def _hello(self):
        print('hello world')

    def __call__(self, *args, **kwargs):
        print('call')

ren = People()	-->执行__init__
ren()	-->执行__call__

7、__dict__ 
  通过类进行调用会获取类的所有属性及方法。
  通过对象进行调用会获取对象的属性。
  直接通过 print(对象.__dict__,或者类.__dict__)进行打印

8、__str__
  如果在一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值
  当然如果直接在交互模式键入类名,然后依旧会有对象提示,因为这个输出是由__repr__进行控制的,通常__repr__和__str__的代码都是相同的,如果要修改 需要定义一个__repr__函数,或者直接等同于str:__repr__ = __str__

class People(object):
    'hello everyone'
    pass

    def __str__(self):
        return 'this is str'

ren = People()
print(People()) -->会打印__repr__的返回值
ren -->会打印__str__的返回值

9、__getitem__\__setitem__\__delitem__

  类似字典的索引形式,操作对象

    • getitem:func[key] 时出发
    • setitem:func[key] = value 时触发
    • delitem: del func[key] 时触发

  适用场景:用起来简单,根本不用关心对象的类型,和字典一样使用一种统一的接口实现。
  否则,只能通过反射去实现(会拖慢程序的运行效率)

class Foo:

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

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __getitem__(self, item):
        return self.__dict__[item]

    def __delitem__(self, key):
        del self.__dict__[key]

obj = Foo('daxin',18)     #实例化
obj['name'] = 'daxin666'     #__settitem__
print(obj['age'])         # __getitem__
del obj['name']        # __delitem__

10、__getslice__/__setslice__/__delslice__
  用于分片操作,如列表 。3.x中取消了,只在2.x中存在

class Foo(object):

    def __getslice__(self, i, j):
        print '__getslice__',i,j

    def __setslice__(self, i, j, sequence):
        print '__setslice__',i,j
    
    def __delslice__(self, i, j):
        print '__delslice__',i,j

obj = Foo()

obj[-1:1]     # 自动触发执行 __getslice__
obj[0:1] = [11,22,33,44]     # 自动触发执行 __setslice__
del obj[0:2]     # 自动触发执行 __delslice__     

11、__setattr__,__getattr__,__delattr__:
  设置属性就会触发 __setattr__ 的执行,而默认的__setattr__ 默认就会 self.__dict__[key] = value,所以如果改写了,没有赋值操作的话,就不会开辟名称空间
  __getattr__,只有在属性不存在的时候,才会触发。
  __delattr__,删除一个属性时触发

class Foo:

    def __init__(self,x):
        self.x = 1

    def __setattr__(self, key, value):
        self.__dict__[key] = value

    def __getattr__(self, item):
        return 'The %s is not exist' % item

    def __delattr__(self, item):
        self.__dict__.pop(item)


obj = Foo(10)    #触发__Setattr__方法
print(obj.name)    #如果属性不存在,才会触发getattr方法

PS:当放问的是一个不存在的方法,也是可以使用__getattr__ 来处理的

class Student(object):

    def __getattr__(self, attr):
        if attr=='age':
            return lambda x: x + 3     # 用户传递的12,将赋值给x,然后返回x+3

s = Student()
print(s.age(12))

PS:作为函数返回时,注意只能返回函数。

class Chain(object):

    def __init__(self, path='/users'):
        self._path = path

    def __getattr__(self, path):
        if path == 'users':
            return lambda s: Chain('%s/%s' % (self._path, s))
        return Chain('%s/%s' % (self._path, path))

    def __str__(self):
        return self._path

    __repr__ = __str__


print(Chain().users('abc').repos)

# 根据传入的用户名自动生成API接口(github)

# ------------------------------- 定义函数进行返回 ----------------------------------
class Chain(object):

    def __init__(self, path='/users'):
        self._path = path

    def __getattr__(self, path):
        if path == 'users':
            return self._user        # 只能返回函数
        return Chain('%s/%s' % (self._path, path))

    def _user(self,item):            # 用于接受传递的参数
        print(item)
        return Chain('%s/%s' % (self._path, item))


    def __str__(self):
        return self._path

    __repr__ = __str__


print(Chain().users('abc').repos)
 1 class Chain(object):
 2 
 3     def __init__(self, path=''):
 4         self._path = path
 5 
 6     def __getattr__(self, path):
 7         return Chain('%s/%s' % (self._path, path))
 8 
 9     def __str__(self):
10         return self._path
11 
12     __repr__ = __str__
13 
14 print(Chain().status.user.timeline.list)
15 # '/status/user/timeline/list'
根据传递的参数,自动生成URL

12、__next__、__iter__ 实现迭代器协议
  通过 yield 可以实现迭代器
  __next__ next 一次获取一个值
  __iter__ 非迭代器通过__iter__获取一个迭代对象,迭代器执行__iter__方法,获取迭代器本身

class range():


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


    def __next__(self):
        x = self.n
        self.n += 1
        return x

    def __iter__(self):
        return self


obj = range(1)
print(next(obj))   #执行对象的 __next__ 方法
print(next(obj))
print(next(obj))
from collections import Iterator
print(isinstance(obj,Iterator))   # 对象是可迭代的

实现一个简单的range:

 1 class range():
 2 
 3 
 4     def __init__(self,start,stop,step=1):
 5         self.start = start
 6         self.stop = stop
 7         self.step = step
 8 
 9     def __next__(self):
10         if self.start >= self.stop:
11             raise StopIteration     #注意迭代器的停止异常是StopIteration
12         x = self.start
13         self.start += self.step
14         return x
15 
16     def __iter__(self):
17         return self
18 
19 
20 for i in range(1,5,2):
21     print(i)
View Code

13、__enter__ 和 __exit__ 
  上下文管理协议(格式:with open('a.txt') as fd)
  with 触发 __enter__ 方法
  接收的时候触发 __exit__ 方法
  __exit__(exc_type,exc_val,exc_tb)

    • exc_type:异常类型
    • exc_val:异常的值
    • exc_tb:异常的追踪器

  在__exit__里面做一些清理工作,如果函数 return True 表示不上报异常,那么后续的代码就会继续执行,否则将会中断

class Open(object):

    def __init__(self,filename,mode='r',encoding='UTF-8'):
        self.filename = filename
        self.mode = mode
        self.encoding = encoding
        self.f = open(self.filename,mode = self.mode,encoding = self.encoding)

    def __enter__(self):
        print('from __enter__')
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('from __exit__')
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        self.f.close()
        # return True    #如果这里return True 异常将不会被抛出



with Open('a.txt','w') as fd:     #触发init和 enter方法
    print('123')             #打印完毕后,触发exit方法
   1/0           #这里由于除数为0,所以会上报异常,通过exit的 exc_type exc_val  exc_tb  进行显示

14、__new__和__metaclass__
  __new__就是用来创建实例的,而__init__其实是在__new__中调用的,由于父类中已经写了__new__方法,如果我们要重写,就需要进行继承,大多数情况下只有在定制类的时候会用到,而__new__方法是由__call__方法执行的

创建class的方法就是使用type()函数。
  type()函数既可以返回一个对象的类型,又可以创建出新的类型

例子:

def talk(self,word = 'world'):
    self.word = word
    print('hello %s' % self.word)

People = type('People',(object,),dict(say=talk)) 当然后面的字典也可以换成{'say':talk}
type(类名,父类的元祖(针对继承的情况,可以为空),包含属性的字典(名称和值))
type创建class的方法:
    参数1:class的名称
    参数2:继承的对象
    参数3:class的方法与函数绑定,这里把talk方法,绑定到方法名say上。

通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描class定义的语法,然后调用type()函数创建出class(默认情况下是这样,如果我们定义了__metaclass__,那么就会按照__metaclass__定义的元类去创建)。查找__metaclass__顺序,本类,父类,模块级别,如果都没有__metaclass__才会利用type进行构建

15、__slot__ 

  用于限制可以给类实例绑定的属性

class Student(object):
    __slots__ = ('name','age')    # 这里限制只能给实例添加name,age属性
    def __init__(self,sex):       # 这里传递sex属性,由于没有被允许,所以会报错
        self.sex = sex

a = Student('F')
print(a.sex)

PS:该属性不会被继承

二次加工标准类型(包装)  

例子1:限制list 追加的元素必须是string

class List(list):
    def append(self,p_object):
        if not isinstance(p_object,str):
            raise TypeError('The %s must be str' % p_object)
        super(List,self).append(p_object)


a = List([1,2,3,4,5])
a.append('1')
print(a)

例子2:结合property 

class List(list):

    @property
    def mid(self):
        mid_num = len(self)//2
        return self[mid_num]

a = List([1,2,3,4,5])
a.append('1')
print(a)
print(a.mid)

例子3:改写clear方法,添加权限认证,tag = False

class List(list):

    def clear(self,tag=False):
        if tag:
            super(List, self).clear()
        else:
            raise PermissionError('permissiver')

a = List([1,2,3,4,5])
a.clear(True)

2、改写内置函数(授权)

  自己写的功能已自己为准,自己没有的功能通过授权调用函数来实现

  改写open方法
  __getattr__ + getattr(object,item) 反射

import time
class Open(object):
    def __init__(self,filepath,mode='r',encoding='utf-8'):
        self.filepath = filepath
        self.mode = mode
        self.encoding = encoding
        self.f = open(filepath,mode = self.mode,encoding=self.encoding)    # 得到一个文件描述符,文件描述符的入口改为self.f,由于open有多个参数,所以这里用默认参数

    def write(self,msg):     #等于改写了self.f.write方法
		t = time.strftime('%Y-%m-%d %X')  #定义时间格式
		self.f.write('%s %s' % (t,msg))   #调用self.f的write功能,写入时间,等于改写了write方法

    def __getattr__(self, item):   #得不到method 和 attribute 会读取 对象的 __getattr__方法,
        return getattr(self.f,item)  # 搜索self.f的方法,进行返回,那么加括弧就能执行

obj = Open('a.txt','w',encoding='UTF-8')
obj.write('1111\n')
obj.write('2222\n')
obj.write('3333\n')

 元类的概念,待补充!

 

异常处理

异常追踪信息、异常的类型、异常的值
分为两类:
  语法级别异常: SyntaxError 程序运行前要进行处理
  逻辑上的异常: 使用 try ... except 处理
语法:

try:
    pass --> 要监测的代码
except: --> 捕捉的异常
    pass --> 要进行的处理
else:     --> 没有异常时会执行的
    pass 
finally:   --> 有没有异常都会执行
    pass --> 通常做一些清理、释放资源的工作

except 语句可以有多个,匹配到一个既进行处理

Python的标准异常类

AssertionError	断言语句(assert)失败
AttributeError	尝试访问未知的对象属性
EOFError	用户输入文件末尾标志EOF(Ctrl+d)
FloatingPointError	浮点计算错误
GeneratorExit	generator.close()方法被调用的时候
ImportError	导入模块失败的时候
IndexError	索引超出序列的范围
KeyError	字典中查找一个不存在的关键字
KeyboardInterrupt	用户输入中断键(Ctrl+c)
MemoryError	内存溢出(可通过删除对象释放内存)
NameError	尝试访问一个不存在的变量
NotImplementedError	尚未实现的方法
OSError	操作系统产生的异常(例如打开一个不存在的文件)
OverflowError	数值运算超出最大限制
ReferenceError	弱引用(weak reference)试图访问一个已经被垃圾回收机制回收了的对象
RuntimeError	一般的运行时错误
StopIteration	迭代器没有更多的值
SyntaxError	Python的语法错误
IndentationError	缩进错误
TabError	Tab和空格混合使用
SystemError	Python编译器系统错误
SystemExit	Python编译器进程被关闭
TypeError	不同类型间的无效操作
UnboundLocalError	访问一个未初始化的本地变量(NameError的子类)
UnicodeError	Unicode相关的错误(ValueError的子类)
UnicodeEncodeError	Unicode编码时的错误(UnicodeError的子类)
UnicodeDecodeError	Unicode解码时的错误(UnicodeError的子类)
UnicodeTranslateError	Unicode转换时的错误(UnicodeError的子类)
ValueError	传入无效的参数
ZeroDivisionError	除数为零

注意:
  1、Exception 万能异常,可以匹配到所有的异常
  2、注意异常的先后顺序,当 Exception 和其他异常同时存在时,如果 Exception 放在第一位,那么后面的异常就不会进行匹配了。
误区:
  1、if判断是预防,针对已知的错误进行处理
  2、异常处理不等于 try ... except ,try... except 只是异常处理的一种具体体现形式
  3、多用于无法预估的异常处理(比如socket中,客户端异常断开,服务端需要做相关处理来避免自己程序崩溃)

posted @ 2017-06-19 20:04  SpeicalLife  阅读(494)  评论(0编辑  收藏  举报