Python攻克之路-反射
反射(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(..)