zoukankan      html  css  js  c++  java
  • 面向对象之反射、包装、(定制)

    什么是反射?

    反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省),

    这一概念的提出很快引发了计算机科学领域关于应用反射的研究。它首次被程序语言的设计领域所采用。并在Lisp和面向

    对象方面取得了成绩。

    一、python3中四个可以实现自省的函数,下列方法适用于类和对象

    class BlackMedium:
        feture='Ugly'
        def __init__(self,name,addr):
            self.name=name
            self.addr=addr
        def sell_hourse(self):
            print('[%s]正在卖房子,傻逼才买呢'%self.name)
        def rent_hourse(self):
            print('[%s]正在租房子,傻逼才买呢'%self.name)
    
    b1=BlackMedium('黑中介','殡仪馆')

    1、hasattr(object,name)

    判断object中有没有一个name字符串对应的方法或属性

    class BlackMedium:
        feture='Ugly'
        def __init__(self,name,addr):
            self.name=name
            self.addr=addr
        def sell_hourse(self):
            print('[%s]正在卖房子,傻逼才买呢'%self.name)
        def rent_hourse(self):
            print('[%s]正在租房子,傻逼才买呢'%self.name)
    
    b1=BlackMedium('黑中介','殡仪馆')
    print(b1.__dict__)#{'name': '黑中介', 'addr': '殡仪馆'}
    # b1.name------->b1.__dict__['name]
    print(b1.name)#黑中介
    print(b1.addr)#殡仪馆
    #用hasattr检测类的属性和方法,存在返回TRUE,不存在返回FALSE
    print(hasattr(b1,'name'))#True
    print(hasattr(b1,'addr'))#True
    print(hasattr(b1,'namnmae'))#False
    hasattr(object,name)

    2、getattr(object,name,default=None)

    检测正确时,有属性就返回属性值,有方法就返回方法的内存地址,加()就可以运行

    检测有错误时,不给default赋值会报错,报错时写什么会提示什么

    #检测属性,属性存在就会打印值,属性不存在会打印报错或default
    print(getattr(b1,'name'))#黑中介
    print(getattr(b1,'aaaaaa'))#有报错提示
    print(getattr(b1,'aaaaaa','没有此属性'))#有报错提示:没有此属性
    
    #检测方法,有则返回内存地址,加()就可以运行,没有则报错或提示default信息
    print(getattr(b1,'sell_hourse','无此方法'))#返回sell_hourse方法的内存地址,-------》b1.sell_hourse
    #<bound method BlackMedium.sell_hourse of <__main__.BlackMedium object at 0x0000020EE5447198>>
    #有内存地址加()就可以运行
    func=getattr(b1,'sell_hourse')
    func()#[黑中介]正在卖房子,傻逼才买呢
    
    print(getattr(b1,'jskdkflsd','无此方法'))#无此方法
    getattr(object,name,default)

    3、setattr(x,y,z)

    可以增加修改属性,也可以增加方法,

    x传入对象,y传入字符串相当于字典中的key,x传入值相当于字典中的value

    print(b1.__dict__)#{'name': '黑中介', 'addr': '殡仪馆'}
    setattr(b1,'name','SB')#修改属性
    setattr(b1,'sb',True)#增加属性
    print(b1.__dict__)#{'name': 'SB', 'addr': '殡仪馆', 'sb': True}
    setattr(b1,'func',lambda self:self.name+'SB')#增加函数属性
    # print(b1.func(b1))#黑中介SB
    setattr(x,y,z)

    4、delattr(x,y)

    删除属性x,y同上

    print(b1.__dict__)#{'name': '黑中介', 'addr': '殡仪馆'}
    delattr(b1,'name')#删除属性------》del b1.name
    # del b1.name
    print(b1.__dict__)#{'addr': '殡仪馆'}
    setattr(x,y)

    5、动态模块导入

    1、把模块名或文件名以字符串形式传给__import__,如果模块在二级文件内,__import__方法只能拿到最顶级模块
    module_t=__import__('三级菜单')#执行module_t就会执行模块内的代码
    print(module_t)
    
    2import imaplib
    m=imaplib.import_module('文件.三级菜单')#直接定位到三级菜单
    print(m)
    3、导入有*号时,如果模块里面的属性有 _名字 的属性或方法时,
    带 下划线的属性或方法则不能被导入
    from 模块名 import *

     补充:

    一切皆对象,文件也是对象同样可以使用自省的方法

    1、情景:当你写的代码有上万行时(此时已是大佬 ^_^),想不起来某个功能是否完成既可以使用下面的方法来判断

    x=111
    y=222
    #用sys可以导入模块自己,用hasattr可以检测功能是否完成
    import sys
    obj=sys.modules[__name__]
    print(hasattr(obj,'x'))#True
    print(hasattr(obj,'xsdf'))#False
    导入模块自己

    2、情景:做程序开发,每个人写不同的功能,当需要用到别人的功能时不知道是否完成,因此我们可以导入同事写的代码文件,用hasattr判断你需要的功能是否完成

    import test as obj
    print(obj)
    
    print(hasattr(obj,'say_hi'))
    
    if hasattr(obj,'say_hi'):
        func=getattr(obj,'say_hi')
        func()
    
    else:
        print('其他的逻辑')
    导入别人的模块

    二、下划线开头的三种attr方法

    这三种方法是给实例用的和类没关系

    1、__getattr__(self,item)

    只有使用点调用属性且属性不存在时才会触发__getattr__

    class Foo:
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def __getattr__(self, item):
            print('执行__getattr__,item是 %s'%item)#调用不存在属性时触发__getattr__
    
    f1=Foo('飞乐',18)
    print(f1.__dict__)#{'name': '飞乐', 'age': 18}
    f1.name#不会触发__getattr__
    f1.jsdlkf#执行__getattr__,item是 jsdlkf
    __getattr__(self,item)

    2、__delattr__(self,item)

    删除属性时会触发

    class Foo:
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def __delattr__(self, item):
            #只要有删除操作就会触发__delattr__,并不一定能删除,
            # 下面的内容会讲到触发__delattr__并且删除值
            print('执行__delattr__,item是 %s'%item)
    f1=Foo('飞乐',18)
    print(f1.__dict__)#{'name': '飞乐', 'age': 18}
    del f1.age#执行__delattr__,item是 age
    print(f1.__dict__)#{'name': '飞乐', 'age': 18}
    __delattr__(self,item)

    3、__setattr__(self,key,value)

    增加或修改属性会触发__setattr__的执行,在实例化对象时__init__函数属于增加属性操作,也会触发__setattr__的执行 

    class Foo:
        def __init__(self,name,age):#会触发__setattr__
            self.name=name
            self.age=age
        def __setattr__(self, key, value):#添加或修改属性会触发它的执行
            print('执行__setattr__,key: %s value: %s'%(key,value))
            # self.kye=value #一直触发__setattr__无期递归,你好好想想
            self.__dict__[key]=value#应该使用它
    
    f1=Foo('飞乐',18)
    #执行__setattr__,key: name value: 飞乐
    #执行__setattr__,key: age value: 18
    print(f1.__dict__)#{'name': '飞乐', 'age': 18}
    f1.sex='male'#增加属性,执行__setattr__,key: sex value: male
    
    print(f1.name)#飞乐
    f1.name='king'#修改属性,执行__setattr__,key: name value: king
    print(f1.__dict__)#{'name': 'king', 'age': 18, 'sex': 'male'}
    print(f1.name)#king
    __setattr__(self,key,value)

    4、利用attr方法定制属于自己的方法

    根据下方代码可以自己扩展,好好想想

    class Foo:
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def __getattr__(self, item):
            print('%s 属性不存在'%item)
        def __setattr__(self, key, value):
            print('正在设置--------》')
            if type(value) is str:
                # self.key=value  会触发__setattr__递归
                self.__dict__[key]=value
            else:
                print('属性添加必须是字符串')
        def __delattr__(self, item):
            print('不允许删除属性 【%s】'%item)
            #del self.__dict__[item]
            #self.__dict__.pop(item)
    # f1=Foo('飞乐',18)#属性添加必须是字符串
    f1=Foo('飞乐','18')#增加或修改属性会触发__setattr__
    #正在设置--------》
    #正在设置--------》
    f1.name#不会触发__getattr__
    f1.king#触发__getattr__  king 属性不存在
    print(f1.__dict__)#{'name': '飞乐', 'age': '18'}
    f1.name='king'#触发了__setattr__
    print(f1.__dict__)# {'name': 'king', 'age': '18'}
    del f1.name#不允许删除属性 【name】
    定制

    三、包装

    包装标准类型,通过继承和派生进行包装定制属于自己的数据类型

    1、通过继承派生包装

    class List(list):
        def append(self, object):
            if type(object) is str:
                super().append(object)#继承父类的append方法
            else:
                print('类型必须是字符串')
        def show_mid(self):
            mid_index=int(len(self)/2)
            return self[mid_index]
    
    l1=List('helloword')
    print(l1,type(l1))#['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'd'] <class '__main__.List'>
    l1.append('king')
    print(l1)#['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'd', 'king']
    l1.append(3245)#类型必须是字符串类型
    print(l1.show_mid())#w
    定制属于自己的list方法

    2、通过__getattr__授权(包装)

    授权也是一种包装用__getattr__方法,不用继承和派生的方法来实现

    import time
    class Open:
        def __init__(self,filename,mode='r',encoding='utf-8'):
            #用类有两种方法一种是继承另一种是组合
            self.file=open(filename,mode,encoding=encoding)#组合
            self.mode=mode
            self.encoding=encoding
        def write(self,line):
            t=time.strftime('%Y-%m-%d %X')
            self.file.write('%s %s'%(t,line))
    
        def __getattr__(self, item):
            return getattr(self.file,item)#返回item方法的内存地址,
    #f1的属性找不到时会触发__getattr__的执行
    f1=Open('a.txt','w+')
    print(f1.write)#返回的内存地址加()就可以执行
    #<built-in method write of _io.TextIOWrapper object at 0x000002138D1E8B40>
    f1.write('helloword')#把内容写入到文件中
    f1.seek(0)
    print(f1.read())#helloword
    
    #f1的write能找到时
    f1.write('CPU过载过高
    ')
    f1.write('内存不足
    ')
    f1.write('系统被不明病毒攻击
    ')
    f1.seek(0)
    print(f1.read())#读出了定制写入的内容
    # 2018-09-10 22:34:34 helloword2018-09-10 22:34:34 CPU过载过高
    # 2018-09-10 22:34:34 内存不足
    # 2018-09-10 22:34:34 系统被不明病毒攻击
    授权
  • 相关阅读:
    STL源码剖析之_allocate函数
    PAT 1018. Public Bike Management
    PAT 1016. Phone Bills
    PAT 1012. The Best Rank
    PAT 1014. Waiting in Line
    PAT 1026. Table Tennis
    PAT 1017. Queueing at Bank
    STL源码剖析之list的sort函数实现
    吃到鸡蛋好吃,看看是哪只母鸡下的蛋:好用的Sqlite3
    cJSON
  • 原文地址:https://www.cnblogs.com/happyfei/p/9618996.html
Copyright © 2011-2022 走看看