一 面向对象的软件开发
任何程序开发都是先设计 后编程,python中class机制只不过是一种编程的方式。一个软件中所产生的错误或隐藏的错误,未知的错误可能达到惊人的程度,这也不是在设计阶段能完全解决的。
什么是软件工程:软件的开发其实是一整套规范,而我们只学了其中的一小部分。一个完整的开发过程,需要明确每个阶段的任务,在保证一个阶段正确的情况下在进行第二个阶段。
1面向对象分析(object oriented analysis ,OOA)
软件工程中,系统分析阶段要求程序员和用户结合到一起,对用户的需求做出精确分析和明确表述。大方面分析软件系统应该做什么,而不是 该怎么去做。
2 面向对象设计(object oriented design,OOD)
根据面向对象分析阶段形成的需求模型,对每一部分分别进行具体的设计。
首先是类的设计,类的设计可能包含多个层次(利用继承与派生机制)。然后以这些类为基础提出程序设计的思路和方法,包括对算法的设计。
3 面向对象编(object orientedprogramming,OOP)
根据面向对象设计的结果,选择一种计算机语言把它写成程序,可以是python
4 面向对象测试(object oriented test,OOT)
在写好程序后交给用户使用前,必须对程序进行严格的测试,测试的目的是发现程序中的错误并修正它。
面向对的测试是用面向对象的方法进行测试,以类作为测试的基本单元。
5 面向对象维护(object oriendted soft maintenance,OOSM)
正如对任何产品都需要进行售后服务和维护一样,软件在使用时也会出现一些问题,或者软件商想改进软件的性能,这就需要修改程序。
由于使用了面向对象的方法开发程序,使用程序的维护比较容易。
二 isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
1 class Foo(object): 2 pass 3 4 obj = Foo() 5 6 isinstance(obj, Foo)
issubclass(sub, super)检查sub类是否是 super 类的派生类
1 class Foo(object): 2 pass 3 4 class Bar(Foo): 5 pass 6 7 issubclass(Bar, Foo)
三 反射
1 什么是反射:主要是指程序可以访问,检测和修改他本身状态的一种功能(自省)。
2 python中面向对象中的反射:通过字符串形式来操作对象相关的属性,python中一切事物都是对象,所以都可以使用反射。
3 四种可以实现自省的函数
getattr 获取属性
1 # class Teacher: 2 # school='oldbly' 3 # def __init__(self,name,age): 4 # self.name=name 5 # self.age=age 6 # def teach(self): 7 # print('%s is teaching'%self.name) 8 9 # print(getattr(Teacher,'school')) 10 # print(getattr(Teacher,'solasdf',None))
setattr 设置属性
1 # class Teacher: 2 # school='oldbly' 3 # def __init__(self,name,age): 4 # self.name=name 5 # self.age=age 6 # def teach(self): 7 # print('%s is teaching'%self.name) 8 9 # setattr(Teacher,'x',123) 10 # print(Teacher.x)
delattr 删除属性
1 # class Teacher: 2 # school='oldbly' 3 # def __init__(self,name,age): 4 # self.name=name 5 # self.age=age 6 # def teach(self): 7 # print('%s is teaching'%self.name) 8 9 # delattr(Teacher,'school') 10 # print(Teacher.school)
hasattr 检查是否含有某属性
1 # class Teacher: 2 # school='oldbly' 3 # def __init__(self,name,age): 4 # self.name=name 5 # self.age=age 6 # def teach(self): 7 # print('%s is teaching'%self.name) 8 9 10 # print(hasattr(Teacher,'school'))
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')
__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
4 为什么是使用反射和反射的好处
好处一,实现可插拔机制
有两个程序员,一个程序员假如想使用另一个程序员所写的类的时候,但是另一个程序员现在不在了,并且还没有完成他写的类。而这个程序员可以使用反射机制继续完成自己的代码。而另一个程序员回来后再继续完成类的定义,并且去实现这个程序员想要的功能。总之反射的好处是可以事先定义好接口。接口只会在被完成后才会真正执行。这实现了即插即用。其实是一种后期绑定:可以事先把主要逻辑写好(只定义接口)后期在实现接口功能。
另一个程序员还没有实现的全部功能
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('处理其他的逻辑')
好处二:动态导入模块(基于反射当前模块成员)
四 二次加工标准类型(包装)
1包装: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)
练习(clear加权限限制)
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()
2授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__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()
五__del__的用法
当该对象被删除时执行函数内的操作
# import time # class Foo: # def __init__(self,x): # self.x=x # print('connect mysql') #conn=abcdef('192.168.1.10',3306) # # def __del__(self): # '''做一些与这个对象有关的清理操作''' # # conn.close() # # file.close() # print('====>') # f=Foo(10) # del f #f.__del__() # time.sleep(3) # print('主程序')
六__str__用法
改变对象的字符串显示
1 class Teacher: 2 def __init__(self,name,age): 3 self.name=name 4 self.age=age 5 self.courses=[] 6 7 def teach(self): 8 print('%s teach' %self.name) 9 10 def __str__(self): 11 return '<name:%s age:%s>' %(self.name,self.age) 12 13 class Course: 14 def __init__(self,name,price,period): 15 self.name=name 16 self.price=price 17 self.period=period 18 def __str__(self): 19 return '《name:%s price:%s period:%s》' %(self.name,self.price,self.period) 20 21 # egon=Teacher('egon',18) 22 # print(egon) #egon.__str__() 23 # print(egon) #egon.__str__() 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 egon=Teacher('egon',18) 44 # print(egon.courses) 45 python=Course('python',20000,'6mon') 46 openstack=Course('openstack',10,'3mon') 47 linux=Course('linux',1,'1mon') 48 49 egon.courses.append(python) 50 egon.courses.append(openstack) 51 egon.courses.append(linux) 52 53 54 # egon.courses.extend([python,openstack,linux]) 55 print(egon.courses) 56 for obj in egon.courses: 57 print(obj)
七 item系列
1 # l=['a','b','c'] 2 # dic={'a':1} 3 # 4 # print(l[1]) 5 # print(dic['a']) 6 7 class Foo: 8 def __init__(self,name,age,sex): 9 self.name=name 10 self.age=age 11 self.sex=sex 12 def __getitem__(self, item): 13 # print(self,item,type(item)) 14 # return getattr(self,item) 15 return self.__dict__[item] 16 def __setitem__(self, key, value): 17 # setattr(self,key,value) 18 self.__dict__[key]=value 19 20 def __delitem__(self, key): 21 # delattr(self,key) 22 self.__dict__.pop(key) 23 24 def __len__(self): 25 return 10 26 f=Foo('egon',18,'male') 27 # print(f.name) #f['name'] 28 # print(f.age) #f['age'] 29 # print(f.sex) #f['sex'] 30 31 # print(f['name']) 32 33 # f['name']='egon_nb' 34 # print(f.__dict__) 35 # del f['name'] 36 # print(f.__dict__) 37 38 print(len(f))