什么是反射?
1、有时我们要访问某个变量或是方法时并不知道到底有没有这个变量或方法,所以就要做些判断。判断是否存在字符串对应的变量及方法。
2、我们知道访问变量时是不能加引号的,否则会被当成字符串处理。如果要通过字符串找到对应的变量,那该怎么办呢
反射就是用于解决上面两个问题而产生的,所谓反射,按我的理解就是反过来告诉我字符串是什么,是变量or方法
python的反射,它的核心本质其实就是利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动!
还是很难理解?
举个例子:
比如老王往自己的银行卡里面存了一笔钱。
这个数字老王是知道的。如果老王如实交代还好,如果不如实交代。他老婆是不知道的。
如果他老婆想知道这笔钱的数目。他老婆需要拿着这张卡,去银行查流水。
这个就相当是两条路径:
老王,往卡里面,存5000,这个是正向过程。
老王老婆,拿老王(对象)的卡(模块),去查流水(操作),得出老王存了5000。这个是逆向的过程。就像镜子的反射。
![f6d07277933e543b086458dd0f6994e4.png](https://i-blog.csdnimg.cn/blog_migrate/8bf533e3ef8cf108270845c5f385aacf.jpeg)
一般正向的就是,当事人操作
反向的就是非当事人,对当事人的行为推理操作
反射就是用字符串数据类型的变量名去访问变量.
python中访问类或对象的成员有三种方法:
如下所示 obj 为对象 var为变量 func为函数
1、obj.var 或 obj.func()
2、obj.__dict__['var']
3、getattr(obj,'var')
反射当前模块
还可以导入其他模块,利用反射查找该模块是否存在某种方法.
import sys
def s1():
print('s1')
def s2():
print ('s2')
this_module = sys.modules['__main__'] #__main__表示当前文件
print(hasattr(this_module, 's1')) #判断's1'是否在当前文件的方法名中
getattr(this_module, 's2')() #取出
import和__import__()
import作用:
导入/引入一个python标准模块,其中包括.py文件、带有init.py文件的目录;
__import__作用:
同import语句同样的功能,但__import__是一个函数,并且只接收字符串作为参数
- 函数功能用于动态的导入模块,主要用于反射或者延迟加载模块。
- __import__(module)相当于import module
- __import__(package.module)相当于from package import name,如果fromlist不传入值,则返回package对应的模块,如果fromlist传入值,则返回package.module对应的模块。
我动态输入一个模块名,可以随时访问到导入模块中的方法或者变量.
imp = input("请输入模块:")
dd = __import__(imp)# 等价于import imp
inp_func = input("请输入要执行的函数:")
f = getattr(dd,inp_func,None)
#作用:从导入模块中找到你需要调用的函数inp_func,然后
返回一个该函数的引用.没有找到就烦会None
f() # 执行该函数
上面还存在一点点小问题:那就是我的模块名有可能不是在本级目录中存放着
dd = __import__("lib.text.commons") #这样仅仅导入了lib模块
dd = __import__("lib.text.commons",fromlist = True) #改用这种方式就能导入成功
# 等价于import config
inp_func = input("请输入要执行的函数:")
f = getattr(dd,inp_func)
f()
反射:
1. getattr()函数是Python自省的核心函数,具体使用大体如下:class A: def __init__(self):
self.name = 'zhangjing'#self.age='24'def method(self):
print"method print"
Instance = A()
print getattr(Instance , 'name, 'not find') #如果Instance 对象中有属性name则打印self.name的值,否则打印'not find'
print getattr(Instance , 'age', 'not find') #如果Instance 对象中有属性age则打印self.age的值,否则打印'not find'
print getattr(a, 'method', 'default') #如果有方法method,否则打印其地址,否则打印default
print getattr(a, 'method', 'default')() #如果有方法method,运行函数并打印None否则打印default
2. hasattr(object, name)
说明:判断对象object是否包含名为name的特性(hasattr是通过调用getattr(ojbect, name)是否抛出异常来实现的)
3. setattr(object, name, value)
这是相对应的getattr()。参数是一个对象,一个字符串和一个任意值。字符串可能会列出一个现有的属性或一个新的属性。这个函数将值赋给属性的。该对象允许它提供。例如,setattr(x,“foobar”,123)相当于x.foobar = 123。
4. delattr(object, name)
与setattr()相关的一组函数。参数是由一个对象(记住python中一切皆是对象)和一个字符串组成的。string参数必须是对象属性名之一。该函数删除该obj的一个由string指定的属性。delattr(x, 'foobar')=del x.foobar
实例:
基于反射机制模拟web框架路由
需求:比如我们输入:http://www.xxx.com/commons/f1,返回f1的结果。
# 动态导入模块,并执行其中函数url = input("url: ")
target_module, target_func = url.split('/')
m = __import__('lib.'+target_module, fromlist=True)
inp = url.split("/")[-1] # 分割url,并取出url最后一个字符串
if hasattr(m,target_func): # 判断在commons模块中是否存在inp这个字符串
target_func = getattr(m,target_func) # 获取inp的引用
target_func() # 执行
else:
print("404")
这下搞明白了么?
更多精彩,请关注微信公众号:python爱好部落