反射(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()的使用
描述:设置
[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(..)