27 python反射机制( 二 )


# user.pydef add_user():print('添加用户')def del_user():print('删除用户')# commons.pydef login():print("这是一个登陆页面!")def logout():print("这是一个退出页面!")def home():print("这是网站主页面!")# visit.pydef run():inp = input("请输入您想访问页面的url:").strip()# modules代表导入的模块,func代表导入模块里面的方法modules, func = inp.split('/')obj_module = __import__(modules)if hasattr(obj_module, func):getattr(obj_module, func)()else:print("404")if __name__ == '__main__':run()最后执行run函数,结果如下:
请输入您想访问页面的url:user/add_user添加用户请输入您想访问页面的url:user/del_user删除用户现在我们就能体会到__import__的作用了,就是把字符串当做模块去导入 。
但是如果我的网站结构变成下面的
|- visit.py|- commons.py|- user.py|- lib|- __init__.py|- connectdb.py现在我想在??visit???页面中调用??lib???包下??connectdb??模块中的方法,还是用之前的方式调用可以吗?
# connectdb.pydef conn():print("已连接mysql")# visit.pydef run():inp = input("请输入您想访问页面的url:").strip()# modules代表导入的模块,func代表导入模块里面的方法modules, func = inp.split('/')obj_module = __import__('lib.' + modules)if hasattr(obj_module, func):getattr(obj_module, func)()else:print("404")if __name__ == '__main__':run()运行run命令 , 结果如下:
请输入您想访问页面的url:connectdb/conn404结果显示找不到,为了测试调用lib下的模块,我抛弃了对所有同级目录模块的支持,所以我们需要查看__import__源码
def __import__(name, globals=None, locals=None, fromlist=(), level=0): # real signature unknown; restored from __doc__"""__import__(name, globals=None, locals=None, fromlist=(), level=0) -> moduleImport a module. Because this function is meant for use by the Pythoninterpreter and not for general use, it is better to useimportlib.import_module() to programmatically import a module.The globals argument is only used to determine the context;they are not modified.The locals argument is unused.The fromlistshould be a list of names to emulate ``from name import ...'', or anempty list to emulate ``import name''.When importing a module from a package, note that __import__('A.B', ...)returns package A when fromlist is empty, but its submodule B whenfromlist is not empty.The level argument is used to determine whether toperform absolute or relative imports: 0 is absolute, while a positive numberis the number of parent directories to search relative to the current module."""pass??__import__???函数中有一个??fromlist??参数,源码解释说,如果在一个包中导入一个模块,这个参数如果为空,则return这个包对象,如果这个参数不为空,则返回包下面指定的模块对象 , 所以我们上面是返回了包对象,所以会返回404的结果,现在修改如下:
# visit.pydef run():inp = input("请输入您想访问页面的url:").strip()# modules代表导入的模块,func代表导入模块里面的方法modules, func = inp.split('/')# 只新增了fromlist=Trueobj_module = __import__('lib.' + modules, fromlist=True)if hasattr(obj_module, func):getattr(obj_module, func)()else:print("404")if __name__ == '__main__':run()运行run方法,结果如下:
请输入您想访问页面的url:connectdb/conn已连接mysql成功了,但是我写死了lib前缀,相当于抛弃了commonsuser两个导入的功能,所以以上代码并不完善,需求复杂后,还是需要对请求的url做一下判断
def getf(module, func):"""抽出公共部分"""if hasattr(module, func):func = getattr(module, func)func()else:print('404')def run():inp = input("请输入您想访问页面的url:").strip()if len(inp.split('/')) == 2:# modules代表导入的模块,func代表导入模块里面的方法modules, func = inp.split('/')obj_module = __import__(modules)getf(obj_module, func)elif len(inp.split("/")) == 3:p, module, func = inp.split('/')obj_module = __import__(p + '.' + module, fromlist=True)getf(obj_module, func)if __name__ == '__main__':run()运行run函数,结果如下:
请输入您想访问页面的url:lib/connectdb/conn已连接mysql请输入您想访问页面的url:user/add_user添加用户当然你也可以继续优化代码,现在只判断了有1个斜杠和2个斜杠的,如果目录层级更多呢,这个暂时不考虑,本次是为了了解python的反射机制

推荐阅读