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 系统被不明病毒攻击
    授权
  • 相关阅读:
    Java程序,JDK的安装、环境的配置
    Oracle数据库,序列、索引、视图
    Oracle数据库,内置函数小结
    Oracle数据库,join多表关联方式、union结果集合并
    Oracle数据库,模糊查询、去重查询
    Oracle数据库,查询语句、内置函数
    Oracle数据库,数据的增、删、改、查
    Unity 3D-Canvas画布的三种模式
    Unity 3D-Navigation网格导航系统使用教程
    Xlua使用教程、攻略
  • 原文地址:https://www.cnblogs.com/happyfei/p/9618996.html
Copyright © 2011-2022 走看看