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}

 

 

posted @ 2020-11-05 17:03  泉love水  阅读(109)  评论(0编辑  收藏  举报