面向对象高级、异常处理和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')
module_test.py
 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
egon还没有实现全部功能
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('处理其他的逻辑')
lili的代码

好处二:动态导入模块(基于反射当前模块成员)

 

 

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()
练习(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)
模拟range,加步长
 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'
lib/aa.py
1 from lib.aa import C
2 
3 obj = C()
4 print obj.__module__  # 输出 lib.aa,即:输出模块
5 print obj.__class__      # 输出 lib.aa.C,即:输出类
index.py

 

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) #------------------------------->不会执行
View Code

如果__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) #------------------------------->会执行
View Code

 

 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__处理
模拟open

用途或者说好处:

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

 

 

posted @ 2017-06-20 18:44  扑克脸的笔记本  阅读(175)  评论(0编辑  收藏  举报