python面向对象进阶之组合与继承授权及常见内置方法
1、组合
一个类的对象属性封装了另一个类的对象
class School: def __init__(self,name,addr): self.name=name self.addr=addr class Course: def __init__(self, name, price, period, school): self.name=name self.price=price self.period=period self.school=school s1=School('复旦大学','上海') c1=Course('py','100','1',s1) print(c1.name) #py print(c1.school) #<__main__.School object at 0x000000000294C588> print(c1.school.name)#复旦大学
2、继承
如果某些方法或者属性是共有的,可以定义为一个父类,定义其他类时继承父类,可以访问父类的属性或者方法
#python多类继承,寻找方法或者init顺序 #1、左侧优先 2、一条路到底 3、同一个根时最后执行
class BaseRequest: def __init__(self): print('BaseRequest.init') class RequestHandler(BaseRequest): def __init__(self): print('RequestHandler.init') def serve_forever(self): print('RequestHandler.serve_forever') self.process_request() def process_request(self): print('RequestHandler.process_request') class Minx: # def __init__(self): # print('minx.init') def process_request(self): print('minx.process_request') class Son(Minx,RequestHandler): pass obj = Son() obj.serve_forever()
#执行结果
RequestHandler.init
RequestHandler.serve_forever
minx.process_request
#注意
self永远指调用该方法的对象,本例中self指obj,obj = Son()实例化时会按照顺序先找到__init方法执行,随后执行obj.serve_forever()时按照顺序找到了RequestHandler中的server_forever方法,该方法中执行了
self.process_request(),此时self是obj,还会从头开始按照顺序寻找process_request方法执行
3、授权
实现授权的关键点就是覆盖__getattr__()方法,在代码中包含一个对getattr()内建函数的调用。特别调用getattr()以得到默认对象属性(数据属性或者方法)并返回它以便访问或调用。
import time class FileHandle: def __init__(self,file,mode='r',encoding='utf-8'): #self.file=file self.file = open(file, mode, encoding=encoding) self.mode=mode self.encoding=encoding #重写write,实现写入内容时加上时间 def write(self,line): print('执行write方法') print('------------>', line) t = time.strftime('%Y-%m-%d %X') self.file.write('%s %s' % (t, line)) #重写覆盖__getattr__ def __getattr__(self, item): print(item) return getattr(self.file, item) obj=FileHandle('test') #obj.fil #只有在使用点调用属性且属性不存在的时候才会触发__getattr__ 例如obj.fil obj.wri print(obj.read) #FileHandle类中没有read方法,会触发__getattr__方法,从self.file对象中获取read 实际获取到的是obj.file对象的read print(obj.read()) obj1=FileHandle('test','w') obj1.write('1111111111111111\n')
4、常见内置方法
__str__ :使用print时执行改方法,可以改变对象的字符串显示,执行print()和str()都是调用对象.__str__() class Foo: def __init__(self,name): self.name=name def __str__(self): return self.name obj=Foo('123') print(obj) res=str(obj) print(res) # 123 123
__call__ :对象后面加括号,触发执行。 class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__ obj() # 执行 __call__
__module__ 显示当前操作的对象在那个模块 __class__ 显示当前操作的对象的类是什么 print(obj.__module__) print(obj.__class__)
__next__和__iter__实现迭代器协议 class Foo: def __init__(self,x): self.x=x def __iter__(self): return self def __next__(self): if self.x >10: raise StopIteration self.x+=1 return self.x f=Foo(3) for i in f: print(i) # 4 5 6 7 8 9 10 11 说明:for 循环的原理,是先执行对象的__iter__方法使其变为可迭代对象,然后去调用__next__方法,而且for循环可以自动捕捉异常
5、描述符
描述符定义:定义的类中至少实现了__get__(),__set__(),__delete__()中的一个方法。描述符本质上也是一个类
__get__():调用一个属性时,触发 __set__():为一个属性赋值时,触发 __delete__():采用del删除属性时,触发
描述符一共有两种:数据描述符和非数据描述符,描述符使用时必须把描述符定义为另一个类的属性
数据描述符:至少实现了__get__()和__set__()
非数据描述符:仅定义了__get__()
属性访问的优先级顺序
优先级有高到底 1.类属性 2.数据描述符 3.实例属性 4.非数据描述符 5.找不到的属性触发__getattr__()
简单使用及验证
class Foo: def __get__(self, instance, owner): print('执行get') print(instance) print(owner) #未定义__set__时就变为非数据描述符 def __set__(self, instance, value): print('执行set') print(instance) print(value) # #instance.__dict__['name'] = value def __delete__(self, instance): print('执行delete') print(instance) class My: name=Foo()#name 被定义为一个描述符 def __init__(self,name): self.name=name pass #类属性的优先级高于数据描述符 print(My.__dict__)#此时属性字典中'name': <__main__.Foo object at 0x000000000237C1D0> My.name='root' #可以看到此时并未触发Foo类中的__set__ 说明是直接操作类的属性字典,通过My.__dict__可以查看。由此可以得出类属性的优先级高于数据描述符 print(My.__dict__)#此时属性字典中'name': 'root' """ #数据描述符属性高于实例属性 obj=My('root') print(obj.__dict__) obj.name='root'#可以看到为实例属性name赋值时触发了Foo类中__set__方法执行了,而且通过obj.__dict__查看实例属性字典中并没有name(因为此时我们的set方法中实际并未操作属性字典),由此可以得出数据描述符属性高于实例属性 print(obj.__dict__) """ """ #实例属性高于非数据描述符 obj=My('root') print(obj.name)#获取到是root,且并未触发__get__,由此可知实例属性高于非数据描述符 print(obj.__dict__)#{'name': 'root'} """
自定制实现property
def decorate(cls): print('类的装饰器开始运行啦------>') cls.city='shanghai' return cls @decorate #无参:People=decorate(People) class People: def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People('egon',18,3333.3) print(People.__dict__) print(p1.city)
#执行结果
func <function Room.area at 0x000000000292A6A8>
这是我们自己定制的静态属性,r1.area实际是要执行r1.area()
instance <__main__.Room object at 0x000000000293C5F8>
owner <class '__main__.Room'>
1
{'__module__': '__main__', '__init__': <function Room.__init__ at 0x000000000292A598>, 'area': <__main__.Myproperty object at 0x000000000293C4A8>, '__dict__': <attribute '__dict__' of 'Room' objects>, '__weakref__': <attribute '__weakref__' of 'Room' objects>, '__doc__': None}