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)
    

      

  • 相关阅读:
    Cookie、Session和自定义分页
    ORM版学员管理系统 2
    ORM版学员管理系统 3
    ORM版学员管理系统
    Django之ORM
    Django模板语言相关内容
    Django之视图
    MySQL表单查询
    模块和包—Day28
    MySQL windows下cmd安装操作
  • 原文地址:https://www.cnblogs.com/hebbhao/p/9594263.html
Copyright © 2011-2022 走看看