反射(reflection),或称“自省”(introspection)是指Python脚本可以得到一个对象的类型、class、属性、方法等信息。 在某些时候,需要执行对象的某个方法,或是需要给对象的某个字段赋值,而方法名或是字段名在编写代码时并不能确定,需要通过字符串参数传递的形式输入。
通俗描述:通过字符串的形式去操作(增、删、改、查)对象中的成员

1. 基本使用

getattr的使用



class Foo:
    def __init__(self,name,age):
        self.name = name
        self.age = age
obj = Foo('reid',19)  #创建对象,
obj.name              #访问name,name相当于一个变量名
b = 'name'            #与obj.b没有关系,只是内存中存了一个name的字符串
obj.b                 #obj.b实际去init方法中找b



使用b = 'name'获取name, getattr() #去什么东西里获取什么数据



[root@node2 class2]# cat reflect.py 
#!/usr/local/python3/bin/python3
class Foo:
    def __init__(self, name ,age):
        self.name = name
        self.age = age
obj = Foo('reid', 19)
v = getattr(obj, "name") #去obj中获取一个'name'的字符串
print(v)
[root@node2 class2]# python3 reflect.py 
reid                     #根据字符串类型取得值



通过input交互取值



[root@node2 class2]# cat reflect.py
#!/usr/local/python3/bin/python3
class Foo:
    def __init__(self, name ,age):
        self.name = name
        self.age = age
obj = Foo('reid', 19)
inp = input('>>> ')          ###以字符串的形式传递,以字符串的形式去取值
v = getattr(obj, inp)        ###
print(v)
[root@node2 class2]# python3 reflect.py 
>>> name
reid
[root@node2 class2]# python3 reflect.py 
>>> age
19



无论对象中有什么(字段,函数),getattr都可以通过一个字符串的形式取值



class Foo:
    def __init__(self, name ,age):
        self.name = name
        self.age = age
        
    def show(self):                            #show是类的成员,对象可以通过类对象指针找到show
        return "%s--%s" %(self.name, self.age) #show方法是字符串格式化
        
obj = Foo('reid', 19)
func = getattr(obj,'show')          #getattr可以取得init中的name,也可以得到show方法
print(func)                         #func代码show方法

r = func()                          #表示要执行show函数
print(r)
[root@node2 class2]# python3 reflect.py 
<bound method Foo.show of <__main__.Foo object at 0x7fca4f6d3320>>
reid--19



  

hasattr()的使用
描述:判断对象中是否有相应的内容



[root@node2 class2]# cat reflect.py
#!/usr/local/python3/bin/python3
class Foo:
    def __init__(self, name ,age):
        self.name = name
        self.age = age
    def show(self):
        return "%s--%s" %(self.name, self.age)
obj = Foo('reid', 19)
print(hasattr(obj,'name'))       ##是否有name成员 
[root@node2 class2]# python3 reflect.py
True



  

setattr()的使用
描述:设置

如何让repo使用Python3 python refprop_字符串



[root@node2 class2]# cat reflect.py
#!/usr/local/python3/bin/python3
class Foo:
    def __init__(self, name ,age):
        self.name = name
        self.age = age
    def show(self):
        return "%s--%s" %(self.name, self.age)
obj = Foo('reid', 19)
setattr(obj,'k1','v1')            ####存放在对象的内存中,类相当于模板,对象是根据这个模板创建的
print(obj.k1)
[root@node2 class2]# python3 reflect.py
v1



  

delattr()的使用



root@node2 class2]# cat reflect.py 
#!/usr/local/python3/bin/python3
class Foo:
    def __init__(self, name ,age):
        self.name = name
        self.age = age
    def show(self):
        return "%s--%s" %(self.name, self.age)
obj = Foo('reid', 19)
delattr(obj,'name')                         ####
obj.name
[root@node2 class2]# python3 reflect.py
Traceback (most recent call last):
  File "reflect.py", line 10, in <module>
    obj.name
AttributeError: 'Foo' object has no attribute 'name'



  

2.模块级别的反射
通过类找成员



[root@node2 class2]# cat reflect.py 
#!/usr/local/python3/bin/python3
class Foo:
    stat = '123'
    def __init__(self, name ,age):
        self.name = name
        self.age = age

r = getattr(Foo,'stat')     #类也是一个对象
print(r)
[root@node2 class2]# python3 reflect.py
123



一切皆对象,s2也是对象,类中有成员如name,func



[root@node2 class2]# cat s2.py 
#!/usr/local/python3/bin/python3
NAME = 'reid'
def func():
    return 'func'
[root@node2 class2]# cat s1.py 
#!/usr/local/python3/bin/python3
import s2
r1 = s2.NAME
print(r1)
r2 = s2.func()
print(r2)
[root@node2 class2]# python3 s1.py
reid
func



通过getattr来操作



[root@node2 class2]# cat s1.py
#!/usr/local/python3/bin/python3
import s2
r1 = getattr(s2,'NAME')   
print(r1)
r2                       #r2相当于函数名,与func相似,共同指向同一块内存
[root@node2 class2]# python3 s1.py
reid

[root@node2 class2]# cat s1.py
#!/usr/local/python3/bin/python3
import s2
r1 = getattr(s2,'NAME')
print(r1)

r2 = getattr(s2,'func')
print(r2)
[root@node2 class2]# python3 s1.py
reid
<function func at 0x7f56fe7530d0>   #r2相当于函数名,与func相似,共同指向同一块内存

[root@node2 class2]# cat s1.py
#!/usr/local/python3/bin/python3
import s2
r1 = getattr(s2,'NAME')
print(r1)

r2 = getattr(s2,'func')
result = r2()
print(result)
[root@node2 class2]# python3 s1.py
reid
func



获取模块中的类(模块中的成员)



[root@node2 class2]# cat s2.py
#!/usr/local/python3/bin/python3
NAME = 'reid'
def func():
    return 'func'

class Foo:
    def __init__(self):
        self.name = 123

[root@node2 class2]# cat s1.py
#!/usr/local/python3/bin/python3
import s2
r1 = getattr(s2,'NAME')
#print(r1)

r2 = getattr(s2,'func')
result = r2()
#print(result)

cls = getattr(s2,'Foo')
print(cls)
obj = cls()
print(obj)
print(obj.name)
[root@node2 class2]# python3 s1.py
<class 's2.Foo'>
<s2.Foo object at 0x7f9b609f1438>
123



  

3.实例
描述:web中点不同的框框,显示不同的内容,现在使用终端,实现用户输入内容就显示内容
一般写法: 在s2中要定义多个页,example中要做N个判断



[root@node2 class2]# cat s2.py 
#!/usr/local/python3/bin/python3
def f1():
    return 'first page'

def f2():
    return 'news'

def f3():
    return 'big news'

[root@node2 class2]# cat example.py 
#!/usr/local/python3/bin/python3
import s2
inp = input('enter url: ')

if inp == 'f1':
    s2.f1()
elif inp == 'f2'"
    s2.f2()



getattr优化:使用反射实现



[root@node2 class2]# cat example.py
#!/usr/local/python3/bin/python3
import s2
inp = input('enter url: ')

func = getattr(s2,inp)      ##用户输入什么,就取什么
result = func()
print(result)
[root@node2 class2]# python3 example.py
enter url: f1
first page



hasattr判断是否有相应内容



[root@node2 class2]# cat example.py
#!/usr/local/python3/bin/python3
import s2
inp = input('enter url: ')

if hasattr(s2, inp):            ##有相应的内容才操作
    func = getattr(s2,inp)
    result = func()
    print(result)
else:
    print('404')
[root@node2 class2]# python3 example.py
enter url: f2
news
[root@node2 class2]# python3 example.py
enter url: kk
404



  

应用场景
描述:在Python的web框架其中一个实现,基于反射来完成,当访问网页时,相当于发送了http的一个get请求,会带着字符串这个get的请求发送到服务器端,后台收到后,先获取get的字符串,再根据字符串,找到以下类中的方法get去执行



class Handler:
    def get(self):
        print(..)
    def post(self):
        print(..)