zoukankan      html  css  js  c++  java
  • DAY21 反射(hasattr,getattr,setattr,delattr)

    反射

    (1)反射的定义:

      反射就是通过字符串来操作python代码中的对象的属性和方法。

    (2)为什么要用反射?三个场景:

      1.用户输入input

        从用户输入的字符串中,想转换为变量的名字。

      2.文件读取

        从文件中读出的字符串,想转换为变量的名字。

      3.网络


    getattr()

      先看看getattr()的源码的解释:

    def hasattr(*args, **kwargs): # real signature unknown
        """
        Return whether the object has an attribute with the given name.
        
        This is done by calling getattr(obj, name) and catching AttributeError.
        """
        pass
    getattr()源码解释

      具体使用:

      (1)getattr(obj,属性名)----> 传入字符串类型的属性名,返回属性的值,相当于执行了“obj.属性名”

      (2)getattr(obj,方法名)----> 传入字符串类型的方法名,返回对应方法的内存地址。

      谨记:如果第二个参数不存在的话,就会报错。

    class A:
        name = 'he'
        age = 23
    print(A.name)    #he
    print(A.age)       #23
    
    #使用反射的形式,操作类的属性
    print(getattr(A, 'name'))
    >>>
    he
    
    #使用反射操作类中的方法
    class A:
        number = 1
        def func(self):
            print('in the func')
    a = A()
    ret = getattr(a,'func')      #得到了func方法的内存地址
    ret()                              #调用func()方法
    

    hasattr()

    def hasattr(*args, **kwargs): # real signature unknown
        """
        Return whether the object has an attribute with the given name.
        
        This is done by calling getattr(obj, name) and catching AttributeError.
        """
        pass
    hasattr的源码解释

      具体使用:

      hasattr(obj,字符串类型的属性名/方法名)--->判断对象中是否拥有指定属性/方法,返回True/False。

      谨记:所以hasattr经常和getattr一起使用,先用hasattr判断,再使用getattr取值。

    #例子1:通过hasattr判断,再用getattr来取值。
    class A:
        name = 'he'
        age = 23
    
    inp = input('>>>:')
    if hasattr(A,inp):
        print(getattr(A,inp))
    else:
        print('A类中没有对应的属性')
    
    >>>:name
    he
    >>>:sex
    A类中没有对应的属性
    
    
    #例子2
    class Student:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def show(self):
            for key in self.__dict__:                 #__dict__查看对象的所有属性
                print(key,self.__dict__[key])         # key self.__dict__[key]
    
    s = Student('he',23)
    # s.show()
    
    if hasattr(s,'show'):
        func = getattr(s,'show')        #返回方法的内存地址,赋值给func()
        func()
    >>>
    name he
    age 23
    

    setattr()

    def setattr(x, y, v): # real signature unknown; restored from __doc__
        """
        Sets the named attribute on the given object to the specified value.
        
        setattr(x, 'y', v) is equivalent to ``x.y = v''
        """
        pass
    setattr的源码解释

      具体使用:

      setattr(obj,'name',value) ---->通过反射的方式为一个对象设置属性(增改操作),相当于obj.name=value

    #正常情况下,想给对象设置一个值。
    class Student:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def show(self):
            for key in self.__dict__:      #__dict__查看对象的所有属性
                print(key,self.__dict__[key]) # key self.__dict__[key]
    
    s = Student('he',23)
    s.sex = 'male'
    print(s.sex)
    >>>
    male
    
    #除了上面的方式之外,还有一种方式为对象设置属性,通过反射的形式.
    setattr(s,'sex','male')
    print(s.__dict__)
    print(s.sex)
    >>>
    {'name': 'he', 'age': 23, 'sex': 'male'}
    

      除了给对象绑定属性,还给对象绑定一个函数。

    #创建一个函数,通过setattr给对象绑上这个函数
    class Student:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def show(self):
            for key in self.__dict__:         #__dict__查看对象的所有属性
                print(key,self.__dict__[key]) # key self.__dict__[key]
    
    s = Student('he',23)
    def func1(a,b):
        print(a,b)
    setattr(s,'func',func1)       #把普通函数当做函数添加到对象空间中
    s.func(1,2)
    print(s.__dict__)
    >>>:
    1 2
    {'name': 'he', 'age': 23, 'func': <function func1 at 0x000001F16D252F28>}

    delattr()

      delattr(obj,'name'):通过反射的方式,删除对象中的属性(删除操作)

    class Student:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def show(self):
            for key in self.__dict__:      #__dict__查看对象的所有属性
                print(key,self.__dict__[key]) # key self.__dict__[key]
    
    s = Student('he',23)
    #正常方法
    del s.age
    print(s.__dict__)
    
    #通过delattr反射的方式
    delattr(s,'age')
    print(s.__dict__)
    

      总结:

      (1)hasattr():判断一个对象中是否能够调用一个名字,返回True/False

      (2)getattr():返回一个对象中的名字的值

      (3)setattr():为一个对象设置属性(增加/修改操作)

      (4)delattr():删除一个对象的某个属性(删除操作)


    通过反射来操作模块

      通过上面学习的反射的四种方法,我们知道了如果通过反射来操作类中的属性/方法,但是除了"类名.属性名/方法名","对象名.属性名/方法名"之外,我们还接触过“模块名.函数名()”,那么能否通过反射来操作模块呢?答案是肯定的。

      在python中,一切皆对象,当导入一个模块时,模块其实就可以看成一个对象。

      getattr(模块,'属性名/方法名')

    import sys
    print(getattr(sys, 'path'))       
    >>>
    C:Python36python.exe E:/python_training_s1/day21/day21_training.py
    ['E:\python_training_s1\day21', 'E:\python_training_s1', 'C:\Python36\python36.zip', 
    'C:\Python36\DLLs', 'C:\Python36\lib', 'C:\Python36',
    'C:\Users\hesihao\AppData\Roaming\Python\Python36\site-packages',
    'C:\Python36\lib\site-packages',
    'D:\pycharm\PyCharm 2018.1.4\helpers\pycharm_matplotlib_backend']

    通过反射来操作当前文件

      既然反射能够操作模块,那么当前文件其实也是一个模块,通过sys.modules可以看出,当前文件就是sys.modules['__main__']

    # 方式一:sys.modules[__main__]
    import sys
    name = 'he'
    def foo():
        print('这是本模块的函数foo')
    
    print(getattr(sys.modules['__main__'], 'name'))
    getattr(sys.modules['__main__'], 'foo')()
    >>>
    he
    这是本模块的函数foo
    

      通过sys.modules['__main__']好像完成了要求,但是,仔细想一下,使用__main__表示当前文件,假如在另外一个py文件中把当前文件导入,此时__main__便指向的是另外一个py文件,使用sys.modules['__main__']这种方式显然是不妥的,那么要怎么解决?

      使用sys.modules[__name__]就能完美解决,因为__name__就是'__main__'。

    #通过sys.modules[__name__]反射当前模块
    import sys name = 'he' def foo(): print('这是本模块的函数foo') getattr(sys.modules[__name__],'foo')() >>> 这是本模块的函数foo

      总结:

      sys.modules['__main__'] : __main__会随着文件的不同而不同,存在安全隐患。

      sys.modules[__name__]:__name__不管在哪里导入这个模块,都代表这个文件。

    如何反射来操作当前模块中的类

    import sys
    class Student:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def show(self):
            for key in self.__dict__:      #__dict__查看对象的所有属性
                print(key,self.__dict__[key]) # key self.__dict__[key]
    
    
    main = sys.modules[__name__]
    cls = getattr(main,'Student')
    he = cls('小何',23)
    

      

  • 相关阅读:
    Network (poj1144)
    C. Hongcow Builds A Nation
    ZYB loves Xor I(hud5269)
    D. Chloe and pleasant prizes
    Game(hdu5218)
    约瑟夫环的递推方法
    Misaki's Kiss again(hdu5175)
    Exploration(hdu5222)
    B. Arpa's weak amphitheater and Mehrdad's valuable Hoses
    C. Arpa's loud Owf and Mehrdad's evil plan
  • 原文地址:https://www.cnblogs.com/hebbhao/p/9594263.html
Copyright © 2011-2022 走看看