27 python反射机制

1. 什么是反射?它的核心本质其实就是基于字符串的事件驱动,通过字符串的形式去操作对象的属性或者方法
2. 反射的优点一个概念被提出来,就是要明白它的优点有哪些,这样我们才能知道为什么要使用反射 。
2.1 场景构造开发1个网站 , 由两个文件组成,一个是具体执行操作的文件commons.py,一个是入口文件visit.py需求:需要在入口文件中设置让用户输入url,根据用户输入的url去执行相应的操作
# commons.pydef login():print("这是一个登陆页面!")def logout():print("这是一个退出页面!")def home():print("这是网站主页面!")【27 python反射机制】# visit.pyimport commonsdef run():inp = input("请输入您想访问页面的url:").strip()if inp == 'login':commons.login()elif inp == 'logout':commons.logout()elif inp == 'index':commons.home()else:print('404')if __name__ == '__main__':run()运行run方法后,结果如下:
请输入您想访问页面的url:login这是一个登陆页面!提问:上面使用if判断,根据每一个url请求去执行指定的函数 , 若commons.py中有100个操作,再使用if判断就不合适了回答:使用python反射机制,commons.py文件内容不变,修改visit.py文件,内容如下
import commonsdef run():inp = input("请输入您想访问页面的url:").strip()if hasattr(commons, inp):getattr(commons, inp)()else:print("404")if __name__ == '__main__':run()使用这几行代码,可以应对??commons.py??文件中任意多个页面函数的调用!
反射中的内置函数getattrdef getattr(object, name, default=None): # known special case of getattr"""getattr(object, name[, default]) -> valueGet a named attribute from an object; getattr(x, 'y') is equivalent to x.y.When a default argument is given, it is returned when the attribute doesn'texist; without it, an exception is raised in that case."""pass??getattr()???函数的第一个参数需要是个对象,上面的例子中,我导入了自定义的commons模块,commons就是个对象;第二个参数是指定前面对象中的一个方法名称 。??getattr(x, 'y')??? 等价于执行了 ?x.y??? 。假如第二个参数输入了前面对象中不存在的方法,该函数会抛出异常并退出 。所以这个时候,为了程序的健壮性,我们需要先判断一下该对象中有没有这个方法,于是用到了??hasattr()??函数
hasattrdef hasattr(*args, **kwargs): # real signature unknown"""Return whether the object has an attribute with the given name.This is done by calling getattr(obj, name) and catching AttributeError."""pass??hasattr()???函数返回对象是否拥有指定名称的属性,简单的说就是检查在第一个参数的对象中,能否找到与第二参数名相同的方法 。源码的解释还说,该函数的实现其实就是调用了??getattr()???函数,只不过它捕获了异常而已 。所以通过这个函数 , 我们可以先去判断对象中有没有这个方法 , 有则使用??getattr()??来获取该方法 。
setattrdef setattr(x, y, v): # real signature unknown; restored from __doc__"""Sets the named attribute on the given object to the specified value.setattr(x, 'y', v) is equivalent to ``x.y = v''"""pass??setattr()???函数用来给指定对象中的方法重新赋值(将新的函数体/方法体赋值给指定的对象名)仅在本次程序运行的内存中生效 。??setattr(x, 'y', v)??? 等价于 ??x.y = v?
delattrdef delattr(x, y): # real signature unknown; restored from __doc__"""Deletes the named attribute from the given object.delattr(x, 'y') is equivalent to ``del x.y''"""pass删除指定对象中的指定方法,特别提示:只是在本次运行程序的内存中将该方法删除,并没有影响到文件的内容
__import__模块反射接着上面网站的例子 , 现在一个后台文件已经不能满足我的需求,这个时候需要根据职能划分后台文件,现在我又新增了一个??user.py这个用户类的文件 , 也需要导入到首页以备调用 。
但是,上面网站的例子,我已经写死了只能指定commons模块的方法任意调用,现在新增了user模块,那此时我又要使用if判断?答:不用,使用Python自带的函数__import__
由于模块的导入也需要使用Python反射的特性,所以模块名也要加入到url中,所以现在url请求变成了类似于??commons/visit??的形式

推荐阅读