1.反射
在java中经常听到反射,JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性(摘自百度百科)。对比java中反射的定义,在python中就是称为自省的东西。
2.应用场景
在web应用中一个核心的功能就是路由,通过不同的url调用不同的函数来实现不同的操作,当然你可这样实现
def func1():
print 'func1'
def func2():
print 'func2'
url = input().strip()
if url == 'func1':
func1()
elif url == 'func2':
func2()
在python中就可以用自省(反射)来解决这一类问题。当url为func1使,输出func1,这并没有什么问题,但是这里有一个缺陷,如果你的网站非常大,url非常多,这样写就非常的不方便。
3.python自省
自省就是在运行过程让对象自己告诉我们它有什么,自省的四大核心属性:
- dir([obj]): 调用这个方法将返回包含obj大多数属性名的列表(会有一些特殊的属性不包含在内)。obj的默认值是当前的模块对象。
- hasattr(obj, attr): 这个方法用于检查obj是否有一个名为attr的值的属性,返回一个布尔值。
- getattr(obj, attr): 调用这个方法将返回obj中名为attr值的属性的值,例如如果attr为'bar',则返回obj.bar。
- setattr(obj, attr, val): 调用这个方法将给obj的名为attr的值的属性赋值为val。例如如果attr为'bar',则相当于obj.bar = val。
上述的例子可以做如下修改:
class Handle(object):
def func1(self):
print 'func1'
def func2(self):
print 'func2'
handle = Handle()
url = input().strip()
if hasattr(handle, url):
func = getattr(handle, url)
func()
我有见过将所有的func保存在一个字典里,不同的字符串对应不同的执行函数,例如如上述代码所示,完全不需要将所有的东西都写死,这个完全是动态获取执行的。
|
还是那个问题,如果你这张路由表很小,当然没有什么问题,但是一旦处理函数非常多的话,单单维护这张表就很困难了。
python的自省工能就可以非常容易的通过字符串来获取对应的执行函数,简单粗暴。
4.进一步
在web开发中通常会面临这样一个问题,如果我们的web项目非常庞大,夸张一点,各种处理模块成千上万,如果所有的模块都需要导入的话是否太麻烦了,而且后期维护也异常不便。
在python中有一个叫动态加载机制,python提供了一个特殊的方法:__import__(字符串参数)。通过它,我们就可以实现类似的反射功能。__import__()方法会根据参数,动态的导入同名的模块。
上述代码又可以做如下修改:
# module handle.py
class Handle(object):
def func1(self):
print 'func1'
def func2(self):
print 'func2'
# module run.py
module, func = input().strip().split('/')
handle = __import__(module)
handle = handle.Handle()
if hasattr(handle, url):
func = getattr(handle, url)
func()
非常方便,当然在实际的应用中需要严格设计你的web api,风格类似于这种module/func。__import__没有类似于hasattr的功能,所以需要处理好异常。