第八章:Python面向对象知识(1)
大纲:
接口与归一化设计
抽象类
封装之如何隐藏属性
静态属性property
反射
item系列
打印对象信息
析构方法
异常处理
一、接口与归一化设计
接口提取了一群类共同的函数,可以把接口当做一个函数的集合。
然后让子类去实现接口中的函数。
这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。
归一化的好处在于:
1. 归一化让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。
2. 归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合
2.1:就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。
class Interface:#定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。 def read(self): #定接口函数read pass def write(self): #定义接口函数write pass class Txt(Interface): #文本,具体实现read和write def read(self): print('文本数据的读取方法') def write(self): print('文本数据的读取方法') class Sata(Interface): #磁盘,具体实现read和write def read(self): print('硬盘数据的读取方法') def write(self): print('硬盘数据的读取方法') class Process(Interface): def read(self): print('进程数据的读取方法') def write(self): print('进程数据的读取方法')
二、抽象类
抽象类的概念
python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
为什么要有抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案:
import abc #导入模块 目的统一接口,#利用abc模块实现抽象类 class people(metaclass=abc.ABCMeta): @abc.abstractclassmethod def read(self): # '子类必须定义read方法' pass @abc.abstractclassmethod def write(self): # '子类必须定义write方法' pass class Sheng(people): #继承people 方法必定有read和write def read(self): print('Sheng-read') def write(self): print('Sheng-write') def hehe(self): print('Sheng-hehe') class LeLe(people): #继承people 方法必定有read和write def read(self): print('Sheng-read') def write(self): print('Sheng-write') def hehe(self): print('Sheng-hehe') s=Sheng() l=LeLe() s.read() s.hehe() l.read() #这样read和write的接口就归一化了
三、封装之如何隐藏属性
from:http://www.cnblogs.com/Michael--chen/p/6740455.html
1、什么是封装
在程序设计中,封装(Encapsulation)是对具体对象的一种抽象,即将某些部分隐藏起来,在程序外部看不到,其含义是其他程序无法调用。
要了解封装,离不开“私有化”,就是将类或者是函数中的某些属性限制在某个区域之内,外部无法调用。
2、为什么要封装
封装数据的主要原因是:保护隐私(把不想别人知道的东西封装起来)
封装方法的主要原因是:隔离复杂度(比如:电视机,我们看见的就是一个黑匣子,其实里面有很多电器元件,对于用户来说,我们不需要清楚里面都有些元件,电视机把那些电器元件封装在黑匣子里,提供给用户的只是几个按钮接口,通过按钮就能实现对电视机的操作。)
提示:在编程语言里,对外提供的接口(接口可理解为了一个入口),就是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。
3、隐藏方法:
#先看如何隐藏 class Foo: __N=111111 #_Foo__N :定义阶段是变量变形了:_Foo__N def __init__(self,name): self.__Name=name #self._Foo__Name=name def __f1(self): #_Foo__f1 print('f1') def f2(self): self.__f1() #self._Foo__f1() f=Foo('egon') # print(f.__N) #不能引用变量__N因为,语法上已经隐藏,实际上在定义阶段是变量变形了:_Foo__N print(f._Foo__N) #可以直接使用 # f.__f1() #错误 # f.__Name #错误 f.f2() #调用Foo内的__f1,只有在类内再能引用
【问题】
#这种隐藏需要注意的问题:
1:这种隐藏只是一种语法上变形操作,并不会将属性真正隐藏起来
print(Foo.__dict__) # {'__module__': '__main__', '_Foo__N': 111111, '__init__': <function Foo.__init__ at 0x00000000021CBEA0>, '_Foo__f1': <function Foo.__f1 at 0x00000000021CBF28>, 'f2': <function Foo.f2 at 0x00000000021D1048>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
2:这种语法级别的变形,是在类定义阶段发生的,并且只在类定义阶段发生
Foo.__x=123123123123123123123123123123123123123123 print(Foo.__dict__) print(Foo.__x) f.__x=123123123 print(f.__dict__) print(f.__x)
3:在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
class Foo: def __f1(self): #_Foo__f1 print('Foo.f1') def f2(self): self.__f1() #self._Foo_f1 class Bar(Foo): def __f1(self): #_Bar__f1 print('Bar.f1') b=Bar() b.f2()
封装不是单纯意义的隐藏
1:封装数据属性:将属性隐藏起来,然后对外提供访问属性的接口,关键是我们在接口内定制一些控制逻辑从而严格控制使用对数据属性的使用
class People: def __init__(self,name,age): self.__name=name self.__age=age def show_info(self): print('Nameis %s ,Age is %s'%(self.__name,self.__age)) def set_info(self,name,age): #可以控制用户的传入的参数 if not isinstance(name,str): raise TypeError('%s must str.',name) if not isinstance(age,int): raise TypeError('% must int.',age) self.__name=name self.__age=age sheng=People('sheng','13') sheng.show_info() sheng.set_info('lele',234) sheng.show_info()
2:封装函数属性:为了隔离复杂度
#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
#对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
#隔离了复杂度,同时也提升了安全性
class ATM: def __card(self): print('插卡') def __auth(self): print('用户认证') def __input(self): print('输入取款金额') def __print_bill(self): print('打印账单') def __take_money(self): print('取款') def withdraw(self): self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money() a=ATM() a.withdraw()
四、静态属性property
class Foo: @property def f1(self): print('我是静态f1..') f=Foo() # f.f1() f.f1
'''
例:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
体质指数(BMI)=体重(kg)÷身高^2(m)
EX:70kg÷(1.75×1.75)=22.86
'''
class People: def __init__(self,name,weight,height): self.name=name self.weight=weight self.height=height @property def bmi(self): return self.weight/(self.height**2) sheng=People('shengleqi',70,1.70) # print(sheng.bmi()) print(sheng.bmi)
#访问、修改、删除 功能
class People: def __init__(self,name,weight,height): self.__name=name @property def name(self): return self.__name @name.setter def name(self,val): self.__name=val @name.deleter def name(self): del self.__name sheng=People('shengleqi',70,1.70) # print(sheng.bmi()) print(sheng.name) sheng.name='ShengLeQi' #修改属性 print(sheng.name) # del sheng.name # print(sheng.name)
五、反射
概念:通过字符串反射到真实的属性上面。
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
1、 hasattr :判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False。
2、 setattr: 获取对象object的属性或者方法,如果存在打印出来,如果不存在,打印出默认值,默认值可选。
3、 getattr: 给对象的属性赋值,若属性不存在,先创建再赋值。
4、 delattr: 删除对象的属性
#FTP模拟 class Ftpserver: def __init__(self,host,port): self.host=host self.port=port def run(self): while True: cmd=input('>>: ').strip() if not cmd:continue if hasattr(self,cmd): func=getattr(self,cmd) func() def get(self): print('get func') def put(self): print('put func') f=Ftpserver('192.168.1.2',21) f.run()
六、item系列
__setitem__, __getitem, __delitem__
__getitem__(self,key):返回键对应的值。
__setitem__(self,key,value):设置给定键的值
__delitem__(self,key):删除给定键对应的元素。
__len__():返回元素的数量
class Foo: def __getitem__(self, item): print('=====>get') return self.__dict__[item] def __setitem__(self, key, value): self.__dict__[key]=value # setattr(self,key,value) def __delitem__(self, key): self.__dict__.pop(key) f=Foo() # f.x=1 # print(f.x) # print(f.__dict__) f['x']=123123123123 # del f['x'] print(f['x'])
七、打印对象信息__str__
class People: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def __str__(self): return '<name:%s age:%s sex:%s>'%(self.name,self.age,self.sex) p1=People('lele',123,'man') p2=People('hehe',234,'feman') print(p1) print(p2) # <name:lele age:123 sex:man> # <name:hehe age:234 sex:feman>
八、析构方法
“__del__”就是一个析构函数了,当使用del 删除对象时,会调用他本身的析构函数,另外当对象在某个作用域中调用完毕,在跳出其作用域的同时析构函数也会被调用一次,这样可以用来释放内存空间。
__del__()也是可选的,如果不提供,则Python 会在后台提供默认析构函数
class Foo: def __init__(self,x): self.x=x def __del__(self): #在对象资源被释放时触发 print('-----del------') print(self) f=Foo(100000) del f print('=======================>')
九、异常处理
【注意】只有在错误发生的条件无法预知的情况下,才应该加上try...except
try: #代码 except EgonException as e: print(e)
首先try...except是你附加给你的程序的一种异常处理的逻辑,与你的主要的工作是没有关系的,这种东西加的多了,会导致你的代码可读性变差

浙公网安备 33010602011771号