• Python类总结-反射及getattr,setattr


    类反射的四个基本函数

    • hasattr
    • getattr
    • setattr
    • delattr
    #反射
    class BlackMedium:
        feature = 'Ugly'
        def __init__(self,name, addr):
            self.name = name
            self.addr = addr
        def sell_house(self):
            print('[%s]正在卖房子,xx才买呢'%self.name)
    
        def rent_house(self):
            print('[%s]正在卖房子,xx才租呢'%self.name)
    
    b1 = BlackMedium('万成置地','天路园')
    print(b1.__dict__)
    print(hasattr(b1,'name'))
    print(getattr(b1,'name'))
    print(hasattr(b1,'sell_house'))
    print(getattr(b1,'sell_house'))
    func = getattr(b1,'sell_house')
    func()
    # print(getattr(b1,'sell_housedfa'))#没有则报错
    print(getattr(b1,'sell_housedfa','没有这个属性'))#没有则报错
    
    # b1.sb = True 等同于下面
    setattr(b1, 'sb', True)
    setattr(b1, 'func', lambda x: x + 1)
    setattr(b1, 'func1', lambda self: self.name + 'sb')
    print(b1.func(2))
    print(b1.func1(b1))
    print(b1.__dict__)
    
    # del b1.sb 等同于下面
    delattr(b1,'sb')
    print(b1.__dict__)
    
    >>>
    
    {'name': '万成置地', 'addr': '天路园'}
    True
    万成置地
    True
    <bound method BlackMedium.sell_house of <__main__.BlackMedium object at 0x02F5B9B0>>
    [万成置地]正在卖房子,xx才买呢
    没有这个属性
    
    3
    万成置地sb
    {'name': '万成置地', 'addr': '天路园', 'sb': True, 'func': <function <lambda> at 0x00A99AE0>, 'func1': <function <lambda> at 0x00A99C00>}
    {'name': '万成置地', 'addr': '天路园', 'func': <function <lambda> at 0x00A99AE0>, 'func1': <function <lambda> at 0x00A99C00>}
    

    反射动态获取模块的方法名

    class FtpClient:
        def __init__(self,addr):
            print('正在连接服务器[%s]' %addr)
            self.addr = addr
    
    #另外一个模块
    #from module import FtpClient
    f1=FtpClient('192.168.1.1')
    if hasattr(f1,'get'):
        func_get= getattr(f1,'get')
        func_get()
    else:
        print('此方法不存在')
        print('处理其他逻辑')
    

    _getattr_

    class Foo:
        x = 1
        def __init__(self, y):
            self.y = y
    
        def __getattr__(self, item):
            print("执行_getattr__")
    
    f1 =  Foo(10)
    print(f1.y)
    print(getattr(f1,'y'))
    f1.sssss#__getattr__调用一个不存在的属性时才会触发
    
    >>>
    10
    10
    执行_getattr__
    

    _delattr_

    class Foo:
        x = 1
        def __init__(self, y):
            self.y = y
    
        def __delattr__(self, item):
            print("执行__delattr__")
    
    f1 =  Foo(10)
    del f1.y #删除时就触发__delattr__
    del f1.x #删除时就触发__delattr__
    
    >>>
    执行__delattr__
    执行__delattr__
    
    

    _setattr_

    class Foo:
        x = 1
        def __init__(self, y):
            self.y = y
    
        def __setattr__(self, key, value):
            print("执行__setattr__")
            # self.key = value#会出现递归错
            self.__dict__[key]=value #必须要这么设置
    
    f1 =  Foo(10)
    print(f1.__dict__)
    f1.z = 2
    print(f1.__dict__)
    
    • 利用__setattr__,__getattr__限制类的属性必须是字符串类型
    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __getattr__(self,item):
            print("你找的属性[%s]不存在"%item)
    
        def __setattr__(self, key, value):
            print("执行__setattr__", key, value)
            if type(value) is str:
                print('开始设置')
                self.__dict__[key] = value
            else:
                print('必须是字符串')
    
    
    f1 = Foo("alex") #只有是字符串才能添加到Foo, Foo的属性必须是字符串
    f1.age = 19
    
    >>>
    执行__setattr__ name alex
    开始设置
    执行__setattr__ age 19
    必须是字符串
    {'name': 'alex'}
    

    setattr, __delattr__的实际使用举例

    class Foo:
        def __init__(self,name):
            self.name = name
    
        def __getattr__(self,item):
            print("你找的属性[%s]不存在"%item)
    
        def __setattr__(self, key, value):
            print("执行__setattr__", key, value)
            if type(value) is str:
                print('开始设置')
                self.__dict__[key] = value
            else:
                print('必须是字符串')
    
        def __delattr__(self, item):
            print("执行__delattr__", item)
            #del self.item 不能这么用
            self.__dict__.pop(item)
    
    f1 = Foo("alex") #只有是字符串才能添加到Foo, Foo的属性必须是字符串
    print(f1.__dict__)
    del f1.name
    print(f1.__dict__)
    

    标准类型的二次包装

    class List(list): #基础list类
        def append(self, p_object):
            if type(p_object) is str:
                # list.append(self,p_object)
                super().append(p_object)
                print("必须追加字符串")
        def show_middle(self):
            mid_index = int(len(self)/2)
            return self[mid_index]
    
    l1 = List("hello*world")
    l1.append(11111)
    l1.append('test')
    print(l1)
    
    # l2 =list("hello*world")
    #
    # print(l2,type(l2))
    # print(l1,type(l1))
    # print(l1.show_middle()
    
    >>>
    必须追加字符串
    ['h', 'e', 'l', 'l', 'o', '*', 'w', 'o', 'r', 'l', 'd', 'test']
    
    

    授权

    • 授权是所有更新的功能都是由新类的某部分来处理,但已存在的功能授权给对象的默认属性
    • 授权的关键就是覆盖__getattr__方法
    class Open:
        def __init__(self, filename, mode ='r', encoding = 'utf-8'):
            # self.filename = filename
            self.file=open(filename, mode, encoding=encoding)
            self.mode = mode
            self.encoding = encoding
        def __getattr__(self, item):
            print(item, type(item)) #item是个字符串类型,通过字符串得到一个函数,可以通过getattr
            return getattr(self.file,item) #返回一个方法
    
        # def read(self):
        #     pass
        # def write(self):
        #     pass
    
    f1=Open('a.txt','w')
    print(f1.file)
    print(f1.read) #如果类中没有改方法,触发getattr,read传给item
    
    sys_f = open('b.txt','w+')
    print(getattr(sys_f,'read'))
    
    >>>
    <_io.TextIOWrapper name='a.txt' mode='w' encoding='utf-8'>
    read <class 'str'>
    <built-in method read of _io.TextIOWrapper object at 0x001ECDB0>
    <built-in method read of _io.TextIOWrapper object at 0x001ECE30>
    
    • 组合授权
    #用组合的方式实现文件的操作,即可以进行文件父类的操作(非继承),又可以定制本地的方法
    
    import time
    class Open:
        def __init__(self, filename, mode ='r', encoding = 'utf-8'):
            # self.filename = filename
            self.file=open(filename, mode, encoding=encoding) #一定要用这种方法打开文件
            self.mode = mode
            self.encoding = encoding
    
        def write(self,line):
            # 可以定制文件的write方法
            t = time.strftime('%Y-%m-%d %X')
            # print('--->',line)
            self.file.write('%s %s'% (t,line))
    
        def __getattr__(self, item):
            # print(item, type(item)) #item是个字符串类型,通过字符串得到一个函数,可以通过getattr
            return getattr(self.file,item) #返回一个方法
    
    f1=Open('a.txt','r+')
    print(f1.file)
    print(f1.read) #如果类中没有改方法,触发getattr,read传给item
    
    # sys_f = open('b.txt','w+')
    # print(getattr(sys_f,'read'))
    
    f1.write('-------------------
    ') #写入a.txt
    f1.write('CPU负载过高 
    ') #写入a.txt
    f1.seek(0) #seek(0)(从头开始)
    # 基于对位置的seek
    # 0,以文件开头,不限定打开方式。其它的两种限定要以b模式打开
    # 1, 相对于上次光标停留的位置
    # 2,从文件未尾,倒序。位置要用负数表示
    print(f1.read())
    

    getattr和getattribute的区别及联系

    class Foo:
        def __init__(self,x):
            self.x = x
    
        def __getattr__(self, item):
            #只有在getattribute抛出AttributeError才执行
            print("执行的是getattr")
            # return self.__dict__[item]
        def __getattribute__(self, item):
            # 默认情况无论是否有该属性都优先执行getattribute
            print("执行的是getattribute")
            raise AttributeError('跑出异常了,去执行__getattr__')
            # 只可以抛出AttributeError才raise到getattr
    
    f1 = Foo(10)
    #默认情况无论是否有该属性都优先执行getattribute
    f1.xxxx
    

    反射的妙用-根据URL执行相应目录下面的函数

    
    data = input('please input address:') #需要输入account/login
    array = data.split('/') #分割为account, login
    '''
    #实现更加URL不同分发到不同的函数去处理
    from backend import account
    # 等同于 import backend.account
    # backend.account.login()
    if data == 'account/login':
        account.login()
    elif data == 'account/logout':
        account.logout()    
    '''
    #根据传入的数列的字符串,通过反射动态调用函数
    userspace = __import__('backend.'+array[0]) #backend为目录
    model = getattr(userspace, array[0]) #需要多一步getattr
    #通过getattr传入函数名称的字符串,调用函数
    func = getattr(model, array[1])
    func()
    
    >>>
    please input address:admin/index
    欢迎登陆后台管理
    
    调用backend目录下admin.py下index函数
    
    admin.py
    def index():
        print('欢迎登陆后台管理')
    
    
    
  • 相关阅读:
    嵌套矩形
    Multiplication Puzzle
    animate.css在vue项目中的使用
    服务器相关知识
    webpack-cli安装和插件的安装
    新买阿里云linux服务器如何设置账号密码xshell远程登陆
    主流请求库axios库的使用
    什么是回调函数
    js------match() 方法
    cookie
  • 原文地址:https://www.cnblogs.com/konglinqingfeng/p/9644889.html
Copyright © 2020-2023  润新知