反射: 以字符串类型的变量名或方法名去操作变量或方法 -> hasattr() getattr() setattr() delattr()

hasattr(对象, '变量名/方法名') -> 判断对象是否有该变量/方法

class Reflection:
    def __init__(self):
        self.age = 22

r = Reflection()
print(hasattr(r, 'age'))  # True

getattr(对象, '变量名/方法名') -> 以字符串类型的变量名或方法名去操作变量或方法

  • hasattr() 一般配合着 getattr() 使用

class Reflection:
    def __init__(self):
        self.age = 22

r = Reflection()
if hasattr(r, 'age'):  # 判断对象是否有该属性
    a = getattr(r, 'age')  # 以字符串类型的属性名去获取对象中的属性值
    print(a)  # 22

setattr(对象, '变量名', 值) -> 设置或修改变量 -> 没啥用

class SetEdit(): pass
s = SetEdit()

setattr(s, 'name', 'Kevin')  # 设置或需改变量名 

print(s.name)  # Kevin

delattr(对象, '变量名') -> 删除一个变量 -> 没啥用

class SetEdit():
    def __init__(self):
        self.name = 'Kevin'

s = SetEdit()

delattr(s, 'name')  # 删除一个变量

print(s.name)  # 报错

1. 反射对象的属性和方法

  • 反射对象属性

class Reflection:
    def __init__(self):
        self.age = 22

r = Reflection()
if hasattr(r, 'age'):  # 判断对象是否有该属性
    a = getattr(r, 'age')  # 以字符串类型的属性名去获取对象中的属性值
    print(a)

  • 反射对象方法

class Reflection:
    def r_fn(self):
        print('对象中的方法')

r = Reflection()
if hasattr(r, 'r_fn'):  # 判断对象是否有该方法
    rFn = getattr(r, 'r_fn')  # 返回值:绑定方法 -> 以字符串类型的方法名去获取对象中的方法
    print(rFn)  # <bound method Reflection.r_fn of <__main__.Reflection object at 0x00000264ABEF1F98>>
    rFn()  # 调用绑定方法

2. 反射类的静态属性/类方法/静态方法

  • 反射类的静态属性

class Reflection:
    static_attr = '静态属性'

if hasattr(Reflection, 'static_attr'):  # 判断类中是否有该静态属性
    s_a = getattr(Reflection, 'static_attr')  # 以字符串类型的静态属性名去获取类中的静态属性值
    print(s_a)  # 静态属性

  • 反射类的类方法

class Reflection:
    @classmethod
    def rc_fn(cls):
        print('类方法')

if hasattr(Reflection, 'rc_fn'):  # 判断类中是否有该类方法
    rcFn = getattr(Reflection, 'rc_fn')  # 返回值:绑定方法 -> 以字符串类型的类方法名去获取类中的类方法
    print(rcFn)  # <bound method Reflection.rc_fn of <class '__main__.Reflection'>>
    rcFn()  # 调用绑定方法

  • 反射类的静态方法

class Reflection:
    @staticmethod
    def s_fn():
        print('静态方法')

if hasattr(Reflection, 's_fn'):  # 判断类中是否有该静态方法
    s_fn = getattr(Reflection, 's_fn')  # 以字符串类型的静态方法名去获取类中的静态方法
    print(s_fn)  # <function Reflection.s_fn at 0x0000029324FB6C80>
    s_fn()  # 调用方法

3. 在类中反射类自身的属性和方法

  • 在类中反射类自身的属性

class Reflection:

    def __init__(self):
        self.age = 18

    def ref_fn(self):
        if hasattr(self, 'age'):  # 判断self中是否有该属性
            age = getattr(self, 'age')  # 以字符串类型的属性名去获取self中的属性值
            print(age)  # 18


r = Reflection()
r.ref_fn()

  • 在类中反射类自身的静态属性

class Reflection:
    static_attr = '静态属性'

    def ref_fn(self):
        if hasattr(self, 'static_attr'):  # 判断self中是否有该静态属性
            static_attr = getattr(self, 'static_attr')  # 以字符串类型的静态属性名去获取self中的静态属性值
            print(static_attr)  # '静态属性'


r = Reflection()
r.ref_fn()  

  • 在类中反射类自身的方法

class Reflection:

    def fn(self):
        print('类的方法')

    def ref_fn(self):
        if hasattr(self, 'fn'):  # 判断self中是否有该方法
            fn = getattr(self, 'fn')  # 以字符串类型的方法名去获取self中的方法
            print(fn)  # <bound method Reflection.fn of <__main__.Reflection object at 0x000001DC9616E908>>
            fn()  # 类的方法


r = Reflection()
r.ref_fn()

4. 反射模块的变量和方法

# my.py

my_data = '数据'

def my_fn():
    print('模块中的方法')

import my

# 反射模块中的变量
if hasattr(my, 'my_data'):
    m_d = getattr(my, 'my_data')
    print(m_d)

# 反射模块中的方法
if hasattr(my, 'my_fn'):
    my_fn = getattr(my, 'my_fn')
    my_fn()

5. 反射内置模块

import time

if hasattr(time, 'time'):
    t_s = getattr(time, 'time')() # 直接调用通过 getattr 获取到的方法
    print(t_s)  # 1550023996.0530589

6. 反射自身模块(自身脚本文件)的变量和函数

import sys

year = 2019

def y_fn(s):
    print(s)


# 通过 sys.modules 获取当前模块

# self_module = sys.modules['__main__']

self_module = sys.modules[__name__]  # 最好不要使用 '__main__' 去获取当前模块,虽然 __main__ 代表当前模块名,因为如果当前模块是要被引用的那么此时的 __main__ 指向的是引用该模块的文件,通过 __name__ 可以动态的获取当前的模块名


# 获取当前模块的变量
print(getattr(self_module, 'year'))
print(getattr(sys.modules[__name__], 'year'))  # 推荐使用

# 获取当前模块的方法并且调用
getattr(self_module, 'y_fn')('今年是2019年')
getattr(sys.modules[__name__], 'y_fn')('今年是2019年')  # 推荐使用

7. 通过反射获取到的方法的执行方式

  • 将方法赋值后再调用

class Reflection:
    def r_fn(self, s):
        print(s)

r = Reflection()
if hasattr(r, 'r_fn'):
    rFn = getattr(r, 'r_fn')
    rFn('调用通过反射得到的方法')

  • 直接调用方法 -> 因为 getattr(对象, '方法名') 返回的就是一个函数或方法,所以可以直接在后面加()执行

class Reflection:
    def r_fn(self, s):
        print(s)

r = Reflection()
if hasattr(r, 'r_fn'):
    getattr(r, 'r_fn')('调用通过反射得到的方法')

8. 使用反射的例子

class Teacher:
    dic = {'查看学生信息': 'show_student', '查看讲师信息': 'show_teacher'}

    def __init__(self):
        self.name = 'Kevin'

    def show_student(self):
        print('查看学生信息')

    def show_teacher(self):
        print('查看讲师信息')

t = Teacher()
print(hasattr(t, 'name'))  # True

for k in Teacher.dic:
    print(k)

key = input('请输入需求:')
if hasattr(t, Teacher.dic[key]):  # 先检测对象中是否有该对象
    print(getattr(t, 'name'))
    func = getattr(t, Teacher.dic[key])  # 以字符串的形式调用变量/属性/函数/方法
    func()