zoukankan      html  css  js  c++  java
  • 反射和__setattr__,__delattr__,__getattr__用法

    反射

    什么是反射:反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

    python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

    四个可以实现自省的函数

    下列方法适用于类和对象(一切皆对象,类本身也是一个对象)


    #hasattr 判断object中有没有一个name字符串对应的方法或属性
    #getattr 用于以字符串的形式去传入对象的字典中寻找函数
    #setattr 如果该值存在,就覆盖,不存在就添加
    #delattr 如果该值存在就删除,不存在报错

    hasattr(obj,'属性') #obj.属性  是否存在
    getattr(obj,'属性') #获取obj.属性   不存在则报错
    getattr(obj,'属性','默认值') #获取obj.属性   不存在不会报错,返回那个默认值
    setattr(obj,'属性','属性的值') #obj.属性=属性的值
    delattr(obj,'属性') #del obj.属性

    class Game:
        __game_type = 'cross_f'
        def __init__(self,g_name,player,gun,moeny):
            self.g_name = g_name
            self.g_player = player
            self.g_gun = gun
            self.g_moeny = moeny
        def buy_gun(self):
            print('%s买了一把%s游戏的%s并花费了%s元'%(self.g_player,self.g_name,self.g_gun,self.g_moeny))
    g1 = Game('cf','zk','blt',100)
    
    #hasattr 判断object中有没有一个name字符串对应的方法或属性
    print(hasattr(g1,'name'))     #True或者False
    
    #getattr 用于以字符串的形式去传入对象的字典中寻找函数
    a = getattr(g1,'g_name1','随便定义')#语法getattr(对象,'字符串名',默认参数任意)    #监测g1可不可以调取到某个数据属性和函数属性
    print(a)    #如果存在,数据属性,返回对应的V值,函数返回对应的函数对象,不存在返回设置的默认参数
    #执行结果:随便定义
    
    g1.g_test = 888 #添加函数和覆盖函数
    #setattr 如果该值存在,就覆盖,不存在就添加
    setattr(g1,'g_name','aaa')  #添加函数和覆盖函数,执行效果和g1.g_test = 888一样
    setattr(g1,'g_sex','aaa')  #添加函数和覆盖函数,执行效果和g1.g_sex = aaa一样
    print(g1.__dict__)
    #执行结果:{'g_name': 'aaa', 'g_moeny': 100, 'g_sex': 'aaa', 'g_gun': 'blt', 'g_test': 888, 'g_player': 'zk'}
    
    
    del g1.g_test
    #delattr 如果该值存在就删除,不存在报错
    delattr(g1,'g_name')              #AttributeError: name
    print(g1.__dict__)
    #执行结果:{'g_moeny': 100, 'g_player': 'zk', 'g_gun': 'blt', 'g_sex': 'aaa'}
    
    

    通过__import__导入模块

    正常的导入方式:

    import 模块名(文件夹名)as 方法名(文件名)

    通过__import__导入模块

    __import__(name)    #导入模块,无论name有多少层,永远都只返回最顶层
    module_t = __import__('a1.test')    #会执行一次,al下边的test文件,但是不能调用
    print(module_t)     #现在的module_t=a1 如果想要调用a1下边的文件方法,就必须再往下找,
    module_t.test.test1()   #这样才可以调用

    导入importlib模块,通过importlib下的import_module方法导入模块

    import importlib
    m = importlib.import_module('a1.test')      #m得到的就是a1.test这个文件
    m.test1()   #直接用m.m下边的方法直接可以执行

    通过用户输入,实现动态导入

    user_im= input('输入想要导入的模块:')
    imp_in = __import__(user_im)
    a = imp_in.test(1,2);

    具体玩法

    #如果想通过用户输入实现,动态导入模块,并且可以根据用户输入,执行函数
    user_im= input('输入想要导入的模块:')
    #__import__用于以字符串的方式导入模块
    imp_in = __import__(user_im)
    user_infun = input('输入想到执行的函数:')
    #getattr 用于以字符串的形式去某个模块中寻找函数
    in_func = getattr(imp_in,user_infun)
    #获取函数后,加()直接执行
    a = in_func(1,5)
    print(a)

    为什么用反射之反射的好处

    好处一:实现可插拔机制

    有俩程序员,一个alex,一个是egon,alex在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,alex想到了反射,使用了反射机制alex可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现alex想要的功能。

    总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能

    class FtpClient:
        'ftp客户端,但是还么有实现具体的功能'
        def __init__(self,addr):
            print('正在连接服务器[%s]' %addr)
            self.addr=addr
    #from module import FtpClient
    f1=FtpClient('192.168.1.1')
    if hasattr(f1,'get'):    #如果FtpClient存在get方法,就可以进入if判断,并通过getattr执行具体的get方法,处理下边的逻辑
        func_get=getattr(f1,'get')
        func_get()
    else:
        print('---->不存在此方法')#如果不存在,可编写else的逻辑
        print('处理其他的逻辑')
    
    不影响alex的代码编写


    __setattr__,__delattr__,__getattr__用法

    __getattr__只有在使用点调用属性且属性不存在的时候才会触发     比较有用
    __delattr__删除属性的时候会触发
    __setattr__添加/修改属性会触发它的执行
    当你自己写__getattr__、__delattr__、__setattr__方法,系统会调用你写的方法,如果没写,系统调用默认
    class Foo:
        x=1
        def __init__(self,y):
            self.y=y
    
        def __getattr__(self, item):    #self传的是调用者自己  itme传的是调用错误的函数信息
            print('----> from getattr:你找的【%s】属性不存在'%item)
    
    
        def __setattr__(self, key, value):
            print('----> from setattr')
            if type(value) is str:      #判断v值为字符串类型,才能加入字典
                print('执行设置操作')
                # self.key=value #这就无限递归了,你好好想想
                self.__dict__[key] = value.upper()  # 应该使用它   最底层的操作就是在设置属性字典   upper(str)类型的全部大写
            else:
                print('必须是str才能加入')
    
    
    
        def __delattr__(self, item):  #self传的是调用者自己  itme传的是调用错误的函数信息
            print('----> from delattr')
            # del self.item #无限递归了
            #self.__dict__.pop(item)    #同理直接操作字典
    
    f1=Foo(10)
    f1=Foo('asdfgh')
    print(f1.__dict__)
    
    #print(f1.ya)
    # print(getattr(f1,'y'))  #本质就是len(str)------>str.__len__()
    # print(getattr(f1,'不存在的'))   #如果这个参数不存在,那么会执行 __getattr__的参数,如果没有定义__getattr__,会走系统默认的(报错)
    
    #__setattr__添加/修改属性会触发它的执行
    # f1=Foo(10)
    # print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
    # f1.z=3
    # print(f1.__dict__)
    
    #__delattr__删除属性的时候会触发
    #del f1.x    #只要是删除操作就会调用__delattr__函数执行,值不存在也不会报错
    # f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
    # del f1.a
    # print(f1.__dict__)
    
    #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
    # f1.xxxxxx
    
    
    
    
    
    
  • 相关阅读:
    git中文输入显示问题
    how to write a DLL/SO in C/C++ for Python
    python,ctypes
    vc++,dll,lib文件百科
    c++ singleton
    build python on windows
    web前端后端
    动态链接库*.so的编译与使用
    qt,ui,QUiLoader
    qt,script
  • 原文地址:https://www.cnblogs.com/shangpolu/p/6219765.html
Copyright © 2011-2022 走看看