1、组合
一个类的对象属性封装了另一个类的对象
classSchool:def __init__(self,name,addr):
self.name=name
self.addr=addrclassCourse: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>
print(c1.school.name)#复旦大学
2、继承
如果某些方法或者属性是共有的,可以定义为一个父类,定义其他类时继承父类,可以访问父类的属性或者方法
#python多类继承,寻找方法或者init顺序#1、左侧优先 2、一条路到底 3、同一个根时最后执行
classBaseRequest:def __init__(self):print('BaseRequest.init')classRequestHandler(BaseRequest):def __init__(self):print('RequestHandler.init')defserve_forever(self):print('RequestHandler.serve_forever')
self.process_request()defprocess_request(self):print('RequestHandler.process_request')classMinx:#def __init__(self):
#print('minx.init')
defprocess_request(self):print('minx.process_request')classSon(Minx,RequestHandler):passobj=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()以得到默认对象属性(数据属性或者方法)并返回它以便访问或调用。
importtimeclassFileHandle: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,实现写入内容时加上时间
defwrite(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)returngetattr(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__()classFoo:def __init__(self,name):
self.name=namedef __str__(self):returnself.name
obj=Foo('123')print(obj)
res=str(obj)print(res)#123
123
__call__:对象后面加括号,触发执行。classFoo: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__实现迭代器协议
classFoo:def __init__(self,x):
self.x=xdef __iter__(self):returnselfdef __next__(self):if self.x >10:raiseStopIteration
self.x+=1
returnself.x
f=Foo(3)for i inf: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__()
简单使用及验证
classFoo: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)classMy:
name=Foo()#name 被定义为一个描述符
def __init__(self,name):
self.name=namepass
#类属性的优先级高于数据描述符
print(My.__dict__)#此时属性字典中'name': <__main__.foo object at>
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
defdecorate(cls):print('类的装饰器开始运行啦------>')
cls.city='shanghai'
returncls
@decorate#无参:People=decorate(People)
classPeople: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
这是我们自己定制的静态属性,r1.area实际是要执行r1.area()
instance <__main__.room object at>
owner
1
{'__module__': '__main__', '__init__': , 'area': <__main__.myproperty object at>, '__dict__': , '__weakref__': , '__doc__': None}