面向对象高级、异常处理和socket
面向对象高级(http://www.cnblogs.com/linhaifeng/articles/6204014.html)
异常处理
socket
一、上节课复习
继承与派生
1 class Foo1: 2 x=1 3 def test(self): 4 pass 5 6 class Bar(Foo1,): 7 def test(self): 8 super().test() #继承父类函数
新式类:广度优先
经典类:深度优先
多态
同一种事物的多种形态
1 people_obj1.talk() 2 3 pig_obj1.talk() 4 5 dog_obj1.talk() 6 7 def func(obj): 8 9 obj.talk()
封装:
隐藏
1 隐藏 2 class Foo: 3 def __init__(self,age): 4 self.__age=age 5 def get_age(self): 6 return self.__age 7 隔离复杂度 8 obj=Foo() 9 obj.get_age() 10 11 class Foo: 12 def __init__(self,age): 13 self.__age=age 14 @property #可直接调用,不用加() 15 def age(self): 16 return self.__age 17 @age.setter #可设置更改隐藏函数 18 def age(self.arg): 19 self.__age=arg 20 @age.deleter #可删除隐藏函数 21 def age(self): 22 del self.__age 23 24 obj=Foo() 25 obj.age 26 obj.age=3 27 del obj.age
1 #不通过装饰器,通过函数的方式得到函数隐藏的数值,设置并删除值 2 class Foo: 3 def __init__(self,age): 4 self.__age=age 5 def get_age(self): 6 return self.__age 7 def set_age(self.arg): 8 self._age=arg 9 def del_age(self): 10 del self.__age 11 age=property(get_age,set_age,del_age) 12 obj=Foo() 13 #obj.get_age() 14 15 obj.age 16 obj.age=3 17 del obj.age
绑定方法与非绑定方法
绑定方法(绑定给谁就是给谁用的):
绑定到对象的方法,obj.test() ,把obj当做第一个参数传入test
绑定到类的方法:@classmethod,Foo.bind_method(),把Foo当做第一个参数传入bind_method
非绑定方法:
@staticmethod,类与对象都可以调用,但是没有自动传值的效果,就相当于类中定义了一个普通函数
反射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
hasattr(object,name) 判断object中有没有一个name字符串对应的方法或属性
getattr(object, name, default=None)
setattr(x, y, v)
delattr(x, y)
1 class BlackMedium: 2 feature='Ugly' 3 def __init__(self,name,addr): 4 self.name=name 5 self.addr=addr 6 7 def sell_house(self): 8 print('%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼' %self.name) 9 def rent_house(self): 10 print('%s 黑中介租房子啦,傻逼才租呢' %self.name) 11 12 b1=BlackMedium('万成置地','回龙观天露园') 13 14 #检测是否含有某属性 15 print(hasattr(b1,'name')) 16 print(hasattr(b1,'sell_house')) 17 18 #获取属性 19 n=getattr(b1,'name') 20 print(n) 21 func=getattr(b1,'rent_house') 22 func() 23 24 # getattr(b1,'aaaaaaaa') #报错 25 print(getattr(b1,'aaaaaaaa','不存在啊')) 26 27 #设置属性 28 setattr(b1,'sb',True) 29 setattr(b1,'show_name',lambda self:self.name+'sb') 30 print(b1.__dict__) 31 print(b1.show_name(b1)) 32 33 #删除属性 34 delattr(b1,'addr') 35 delattr(b1,'show_name') 36 delattr(b1,'show_name111')#不存在,则报错 37 38 print(b1.__dict__)
1 class Foo(object): 2 3 staticField = "old boy" 4 5 def __init__(self): 6 self.name = 'wupeiqi' 7 8 def func(self): 9 return 'func' 10 11 @staticmethod 12 def bar(): 13 return 'bar' 14 15 print getattr(Foo, 'staticField') 16 print getattr(Foo, 'func') 17 print getattr(Foo, 'bar')
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import sys 5 6 7 def s1(): 8 print 's1' 9 10 11 def s2(): 12 print 's2' 13 14 15 this_module = sys.modules[__name__] 16 17 hasattr(this_module, 's1') 18 getattr(this_module, 's2')
导入其他模块,利用反射查找该模块是否存在某个方法
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 def test(): 5 print('from the test')
1 1 #!/usr/bin/env python 2 2 # -*- coding:utf-8 -*- 3 3 4 4 """ 5 5 程序目录: 6 6 module_test.py 7 7 index.py 8 8 9 9 当前文件: 10 10 index.py 11 11 """ 12 12 13 13 import module_test as obj 14 14 15 15 #obj.test() 16 16 17 17 print(hasattr(obj,'test')) 18 18 19 19 getattr(obj,'test')()
3 为什么用反射之反射的好处
好处一:实现可插拔机制
有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。
总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
1 class FtpClient: 2 'ftp客户端,但是还么有实现具体的功能' 3 def __init__(self,addr): 4 print('正在连接服务器[%s]' %addr) 5 self.addr=addr
1 #from module import FtpClient 2 f1=FtpClient('192.168.1.1') 3 if hasattr(f1,'get'): 4 func_get=getattr(f1,'get') 5 func_get() 6 else: 7 print('---->不存在此方法') 8 print('处理其他的逻辑')
好处二:动态导入模块(基于反射当前模块成员)
4、 __setattr__,__delattr__,__getattr__
1 class Foo: 2 x=1 3 def __init__(self,y): 4 self.y=y 5 6 def __getattr__(self, item): 7 print('----> from getattr:你找的属性不存在') 8 9 10 def __setattr__(self, key, value): 11 print('----> from setattr') 12 # self.key=value #这就无限递归了,你好好想想 13 # self.__dict__[key]=value #应该使用它 14 15 def __delattr__(self, item): 16 print('----> from delattr') 17 # del self.item #无限递归了 18 self.__dict__.pop(item) 19 20 #__setattr__添加/修改属性会触发它的执行 21 f1=Foo(10) 22 print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值 23 f1.z=3 24 print(f1.__dict__) 25 26 #__delattr__删除属性的时候会触发 27 f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作 28 del f1.a 29 print(f1.__dict__) 30 31 #__getattr__只有在使用点调用属性且属性不存在的时候才会触发 32 f1.xxxxxx
5、 二次加工标准类型(包装)
包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)
1 class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid 2 def append(self, p_object): 3 ' 派生自己的append:加上类型检查' 4 if not isinstance(p_object,int): 5 raise TypeError('must be int') 6 super().append(p_object) 7 8 @property 9 def mid(self): 10 '新增自己的属性' 11 index=len(self)//2 12 return self[index] 13 14 l=List([1,2,3,4]) 15 print(l) 16 l.append(5) 17 print(l) 18 # l.append('1111111') #报错,必须为int类型 19 20 print(l.mid) 21 22 #其余的方法都继承list的 23 l.insert(0,-123) 24 print(l) 25 l.clear() 26 print(l)
1 class List(list): 2 def __init__(self,item,tag=False): 3 super().__init__(item) 4 self.tag=tag 5 def append(self, p_object): 6 if not isinstance(p_object,str): 7 raise TypeError 8 super().append(p_object) 9 def clear(self): 10 if not self.tag: 11 raise PermissionError 12 super().clear() 13 14 l=List([1,2,3],False) 15 print(l) 16 print(l.tag) 17 18 l.append('saf') 19 print(l) 20 21 # l.clear() #异常 22 23 l.tag=True 24 l.clear()
授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__getattr__方法
1 import time 2 class FileHandle: 3 def __init__(self,filename,mode='r',encoding='utf-8'): 4 self.file=open(filename,mode,encoding=encoding) 5 def write(self,line): 6 t=time.strftime('%Y-%m-%d %T') 7 self.file.write('%s %s' %(t,line)) 8 9 def __getattr__(self, item): 10 return getattr(self.file,item) 11 12 f1=FileHandle('b.txt','w+') 13 f1.write('你好啊') 14 f1.seek(0) 15 print(f1.read()) 16 f1.close()
1 #_*_coding:utf-8_*_ 2 __author__ = 'Linhaifeng' 3 #我们来加上b模式支持 4 import time 5 class FileHandle: 6 def __init__(self,filename,mode='r',encoding='utf-8'): 7 if 'b' in mode: 8 self.file=open(filename,mode) 9 else: 10 self.file=open(filename,mode,encoding=encoding) 11 self.filename=filename 12 self.mode=mode 13 self.encoding=encoding 14 15 def write(self,line): 16 if 'b' in self.mode: 17 if not isinstance(line,bytes): 18 raise TypeError('must be bytes') 19 self.file.write(line) 20 21 def __getattr__(self, item): 22 return getattr(self.file,item) 23 24 def __str__(self): 25 if 'b' in self.mode: 26 res="<_io.BufferedReader name='%s'>" %self.filename 27 else: 28 res="<_io.TextIOWrapper name='%s' mode='%s' encoding='%s'>" %(self.filename,self.mode,self.encoding) 29 return res 30 f1=FileHandle('b.txt','wb') 31 # f1.write('你好啊啊啊啊啊') #自定制的write,不用在进行encode转成二进制去写了,简单,大气 32 f1.write('你好啊'.encode('utf-8')) 33 print(f1) 34 f1.close()
1 #练习一 2 class List: 3 def __init__(self,seq): 4 self.seq=seq 5 6 def append(self, p_object): 7 ' 派生自己的append加上类型检查,覆盖原有的append' 8 if not isinstance(p_object,int): 9 raise TypeError('must be int') 10 self.seq.append(p_object) 11 12 @property 13 def mid(self): 14 '新增自己的方法' 15 index=len(self.seq)//2 16 return self.seq[index] 17 18 def __getattr__(self, item): 19 return getattr(self.seq,item) 20 21 def __str__(self): 22 return str(self.seq) 23 24 l=List([1,2,3]) 25 print(l) 26 l.append(4) 27 print(l) 28 # l.append('3333333') #报错,必须为int类型 29 30 print(l.mid) 31 32 #基于授权,获得insert方法 33 l.insert(0,-123) 34 print(l) 35 36 37 38 39 40 #练习二 41 class List: 42 def __init__(self,seq,permission=False): 43 self.seq=seq 44 self.permission=permission 45 def clear(self): 46 if not self.permission: 47 raise PermissionError('not allow the operation') 48 self.seq.clear() 49 50 def __getattr__(self, item): 51 return getattr(self.seq,item) 52 53 def __str__(self): 54 return str(self.seq) 55 l=List([1,2,3]) 56 # l.clear() #此时没有权限,抛出异常 57 58 59 l.permission=True 60 print(l) 61 l.clear() 62 print(l) 63 64 #基于授权,获得insert方法 65 l.insert(0,-123) 66 print(l)
六 再看property
一个静态属性property本质就是实现了get,set,delete三种方法
1 class Foo: 2 @property 3 def AAA(self): 4 print('get的时候运行我啊') 5 6 @AAA.setter 7 def AAA(self,value): 8 print('set的时候运行我啊') 9 10 @AAA.deleter 11 def AAA(self): 12 print('delete的时候运行我啊') 13 14 #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter 15 f1=Foo() 16 f1.AAA 17 f1.AAA='aaa' 18 del f1.AAA
1 class Foo: 2 def get_AAA(self): 3 print('get的时候运行我啊') 4 5 def set_AAA(self,value): 6 print('set的时候运行我啊') 7 8 def delete_AAA(self): 9 print('delete的时候运行我啊') 10 AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应 11 12 f1=Foo() 13 f1.AAA 14 f1.AAA='aaa' 15 del f1.AAA
1 class Goods: 2 3 def __init__(self): 4 # 原价 5 self.original_price = 100 6 # 折扣 7 self.discount = 0.8 8 9 @property 10 def price(self): 11 # 实际价格 = 原价 * 折扣 12 new_price = self.original_price * self.discount 13 return new_price 14 15 @price.setter 16 def price(self, value): 17 self.original_price = value 18 19 @price.deleter 20 def price(self): 21 del self.original_price 22 23 24 obj = Goods() 25 obj.price # 获取商品价格 26 obj.price = 200 # 修改商品原价 27 print(obj.price) 28 del obj.price # 删除商品原价
1 #实现类型检测功能 2 3 #第一关: 4 class People: 5 def __init__(self,name): 6 self.name=name 7 8 @property 9 def name(self): 10 return self.name 11 12 # p1=People('alex') #property自动实现了set和get方法属于数据描述符,比实例属性优先级高,所以你这面写会触发property内置的set,抛出异常 13 14 15 #第二关:修订版 16 17 class People: 18 def __init__(self,name): 19 self.name=name #实例化就触发property 20 21 @property 22 def name(self): 23 # return self.name #无限递归 24 print('get------>') 25 return self.DouNiWan 26 27 @name.setter 28 def name(self,value): 29 print('set------>') 30 self.DouNiWan=value 31 32 @name.deleter 33 def name(self): 34 print('delete------>') 35 del self.DouNiWan 36 37 p1=People('alex') #self.name实际是存放到self.DouNiWan里 38 print(p1.name) 39 print(p1.name) 40 print(p1.name) 41 print(p1.__dict__) 42 43 p1.name='egon' 44 print(p1.__dict__) 45 46 del p1.name 47 print(p1.__dict__) 48 49 50 #第三关:加上类型检查 51 class People: 52 def __init__(self,name): 53 self.name=name #实例化就触发property 54 55 @property 56 def name(self): 57 # return self.name #无限递归 58 print('get------>') 59 return self.DouNiWan 60 61 @name.setter 62 def name(self,value): 63 print('set------>') 64 if not isinstance(value,str): 65 raise TypeError('必须是字符串类型') 66 self.DouNiWan=value 67 68 @name.deleter 69 def name(self): 70 print('delete------>') 71 del self.DouNiWan 72 73 p1=People('alex') #self.name实际是存放到self.DouNiWan里 74 p1.name=1
7、 __next__和__iter__实现迭代器协议
1 #_*_coding:utf-8_*_ 2 __author__ = 'Linhaifeng' 3 class Foo: 4 def __init__(self,x): 5 self.x=x 6 7 def __iter__(self): 8 return self 9 10 def __next__(self): 11 n=self.x 12 self.x+=1 13 return self.x 14 15 f=Foo(3) 16 for i in f: 17 print(i)
1 class Foo: 2 def __init__(self,start,stop): 3 self.num=start 4 self.stop=stop 5 def __iter__(self): 6 return self 7 def __next__(self): 8 if self.num >= self.stop: 9 raise StopIteration 10 n=self.num 11 self.num+=1 12 return n 13 14 f=Foo(1,5) 15 from collections import Iterable,Iterator 16 print(isinstance(f,Iterator)) 17 18 for i in Foo(1,5): 19 print(i)
1 class Range: 2 def __init__(self,n,stop,step): 3 self.n=n 4 self.stop=stop 5 self.step=step 6 7 def __next__(self): 8 if self.n >= self.stop: 9 raise StopIteration 10 x=self.n 11 self.n+=self.step 12 return x 13 14 def __iter__(self): 15 return self 16 17 for i in Range(1,7,3): # 18 print(i)
1 class Fib: 2 def __init__(self): 3 self._a=0 4 self._b=1 5 6 def __iter__(self): 7 return self 8 9 def __next__(self): 10 self._a,self._b=self._b,self._a + self._b 11 return self._a 12 13 f1=Fib() 14 15 print(f1.__next__()) 16 print(next(f1)) 17 print(next(f1)) 18 19 for i in f1: 20 if i > 100: 21 break 22 print('%s ' %i,end='')
8、 __module__和__class__
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class C: 5 6 def __init__(self): 7 self.name = ‘SB'
1 from lib.aa import C 2 3 obj = C() 4 print obj.__module__ # 输出 lib.aa,即:输出模块 5 print obj.__class__ # 输出 lib.aa.C,即:输出类
9、 __del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
1 class Foo: 2 3 def __del__(self): 4 print('执行我啦') 5 6 f1=Foo() 7 del f1 8 print('------->') 9 10 #输出结果 11 执行我啦 12 ------->
1 class Foo: 2 3 def __del__(self): 4 print('执行我啦') 5 6 f1=Foo() 7 # del f1 8 print('------->') 9 10 #输出结果 11 -------> 12 执行我啦 13 14 15 16 17 18 #为何啊???
10、 __enter__和__exit__
我们知道在操作文件对象的时候可以这么写
1 with open('a.txt') as f: 2 '代码块'
上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
1 class Open: 2 def __init__(self,name): 3 self.name=name 4 5 def __enter__(self): 6 print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量') 7 # return self 8 def __exit__(self, exc_type, exc_val, exc_tb): 9 print('with中代码块执行完毕时执行我啊') 10 11 12 with Open('a.txt') as f: 13 print('=====>执行代码块') 14 # print(f,f.name)
__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
1 class Open: 2 def __init__(self,name): 3 self.name=name 4 5 def __enter__(self): 6 print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量') 7 8 def __exit__(self, exc_type, exc_val, exc_tb): 9 print('with中代码块执行完毕时执行我啊') 10 print(exc_type) 11 print(exc_val) 12 print(exc_tb) 13 14 15 16 with Open('a.txt') as f: 17 print('=====>执行代码块') 18 raise AttributeError('***着火啦,救火啊***') 19 print('0'*100) #------------------------------->不会执行
如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
1 class Open: 2 def __init__(self,name): 3 self.name=name 4 5 def __enter__(self): 6 print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量') 7 8 def __exit__(self, exc_type, exc_val, exc_tb): 9 print('with中代码块执行完毕时执行我啊') 10 print(exc_type) 11 print(exc_val) 12 print(exc_tb) 13 return True 14 15 16 17 with Open('a.txt') as f: 18 print('=====>执行代码块') 19 raise AttributeError('***着火啦,救火啊***') 20 print('0'*100) #------------------------------->会执行
1 class Open: 2 def __init__(self,filepath,mode='r',encoding='utf-8'): 3 self.filepath=filepath 4 self.mode=mode 5 self.encoding=encoding 6 7 def __enter__(self): 8 # print('enter') 9 self.f=open(self.filepath,mode=self.mode,encoding=self.encoding) 10 return self.f 11 12 def __exit__(self, exc_type, exc_val, exc_tb): 13 # print('exit') 14 self.f.close() 15 return True 16 def __getattr__(self, item): 17 return getattr(self.f,item) 18 19 with Open('a.txt','w') as f: 20 print(f) 21 f.write('aaaaaa') 22 f.wasdf #抛出异常,交给__exit__处理
用途或者说好处:
1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处
11、 __call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
1 class Foo: 2 3 def __init__(self): 4 pass 5 6 def __call__(self, *args, **kwargs): 7 8 print('__call__') 9 10 11 obj = Foo() # 执行 __init__ 12 obj() # 执行 __call__
12、 metaclass