python反射与自省getattr应用篇
在python反射与自省getattr入门篇中理清了getattr中传入的两个参数 对象(object)与 字符串(name)的概念,本篇就结合一些实际案例说说getattr的应有场景。
一、一个简单的应用
1、if调用
在实际应用,经常会遇到定义N个函数,需要根据用户的输入的内容来决定要执行的函数。这里以两个函数为例:
1#!/usr/bin/env python
2# coding=utf-8
3## author: yangbk([email protected])
4## site: www.361way.com
5def funa():
6 print 'running funa ......'
7def funb():
8 print 'running funb ......'
9action = raw_input('请输入地址:')
10if action == "funa":
11 funa()
12elif action == "funb":
13 funb()
如上面的示例的写法,当有N个循环时,需要我们通过if写N个循环。这是很蛋疼的事。能不能简化下写法呢?接着看如何优化。
2、字典map映射
代码如下:
1#!/usr/bin/env python
2# coding=utf-8
3## author: yangbk([email protected])
4## site: www.361way.com
5def funa():
6 print 'processNavigate'
7def funb():
8 print 'processCreateTab'
9action = raw_input('请输入地址:')
10actionMap = {"processNavigate":funa ,"processCreateTab":funb}
11actionMap[action]()
便于理解dict中哪一个是字符串,那一个是函数,我这里稍微修改了下代码。当输入processNavigate时执行函数funa,输入processCreateTab时执行funb。这个不难理解,action为输入的字符串,actionMap[action]得到的是函数名,函数执行时需要在其后加括号。
这个写法较第一种写法固然要好,不过还有一个不好的地方,就是需要维护dict字典,每次有新增的函数时,需要在字典里机里面再加入。能否做过,不论引入的多少函数,都可以直接预使用呢?再看下看。
3、getattr处理
代码如下:
1#!/usr/bin/env python
2# coding=utf-8
3## author: yangbk([email protected])
4## site: www.361way.com
5class getfun:
6 def funa(self):
7 print 'processNavigate'
8 def funb(self):
9 print 'processCreateTab'
10action = raw_input('请输入地址:')
11newfun = getfun()
12fun = getattr(newfun,action)
13fun()
这里我们使用的是类的作法,先创建一个类,将所有函数放在类里。在调用前先实例化该类,不论类里有多少个函数,直接根据输入内容通过getattr调用类里的函数。
4、getattr import引入
再所有的函数存在一个函数库funab.py里,如下:
1#!/usr/bin/env python
2# coding=utf-8
3def funa():
4 print 'running funa ......'
5def funb():
6 print 'running funb ......'
调用方法如下:
1#!/usr/bin/env python
2# coding=utf-8
3## author: yangbk([email protected])
4## site: www.361way.com
5action = raw_input('请输入地址:')
6newfun = __import__('funab')
7fun = getattr(newfun,action)
8fun()
这种写法和方法3基本上差别不大,不过是通过__import__ 的方法引入而已。
二、站点页面引用示例
getattr的另一个常用示例就是在多个web页面的情况下。在入口文件里经常需要用到getattr函数智能处理不同的页面请求。先看下一个常见的页面结构:
1# tree
2.
3├── backend
4│ ├── account.py
5│ ├── account.pyc
6│ ├── admin.py
7│ ├── admin.pyc
8│ ├── __init__.py
9│ └── __init__.pyc
10├── index.py -----> if版入口文件
11└── web.py -----> getattr版入口文件
admin.py和account代码比较简单,单纯为了测试,这里只是print内容。如下:
1[root@361way backend]# cat admin.py
2#!/usr/bin/env python
3# coding=utf-8
4def index():
5 print 'welcome to your, administrator !'
6[root@361way backend]# cat account.py
7#!/usr/bin/env python
8# coding=utf-8
9def login():
10 print 'login now ******* '
11def logout():
12 print 'logout now ******* '
先看下if版的用法:
1[root@361way web]# cat index.py
2#!/usr/bin/env python
3# coding=utf-8
4from backend import account
5data = raw_input('请输入地址:')
6if data == 'account/login':
7 account.login()
8elif data == 'account/logout':
9 account.logout()
这里只import了account ,对登陆和登出做了判断。如果需要登陆后台,还要import admin,并对admin里的方法再做判断。同样如果有还blog 、bbs 、usercenter等相关N个页面时,这个判断结构是不可想象的。如何通过getattr的方法处理实现呢?
1[root@361way web]# cat web.py
2#!/usr/bin/env python
3# coding=utf-8
4## author: yangbk([email protected])
5## site: www.361way.com
6'''
7from backend import account
8data = raw_input('请输入地址:')
9if data == 'account/login':
10 account.login()
11elif data == 'account/logout':
12 account.logout()
13'''
14data = raw_input('请输入地址:')
15array = data.split('/')
16userspance = __import__('backend.'+array[0])
17model = getattr(userspance , array[0])
18func = getattr(model,array[1])
19func()
便于对比,老的if判断的代码我也粘了进去。实际有用的只有后面的一小部分。这里先通过输入内容通过split进行了切分,如输入的account/login ,会切分成数组[ account, login ] ,而输入是admin/index则切分成[ admin, index ] 。由于引用的函数在当前目录下的子目录下,所以这里需要通过backend连接引入。
至于这里为什么是两次getattr调用才能将结果输出呢?这里其实可以使用入门篇里的dir方法查看,也可以通过使用inspect模块进行判断、获取对象。通过dir分析结果如下:
1>>> userspance = __import__('backend.'+ 'admin')
2>>> dir(userspance)
3['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'admin']
4>>> model = getattr(userspance,'admin')
5>>> dir(model)
6['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'index']
7>>> getattr(model,'index')
8<function index at 0x7f572801a9b0>
9>>> getattr(model,'index')()
10welcome to your, administrator !
再看看直接执行后的效果:
1[root@361way web]# python web.py
2请输入地址:admin/index
3welcome to your, administrator !
4[root@361way web]# python web.py
5请输入地址:account/login
6login now ******* [root@361way web]# python web.py
7请输入地址:account/logout
8logout now *******
是不是效果非常好,在backend里论有多少个页面,都可以通过这一段完成调用。完全不用做一大堆的import和if 判断。这里之所以和上面不一样两次getattr,是由于引用内容在子目录下。
三、getattr与传参
在定义getattr相关的函数时,如果import的模块内的函数有参数可传时,也可以通过如下的方法将参数传入。下面这个定义是网上查到的有人对django中的模块引导修改的一个getattr方法。
捐赠本站(Donate)
如您感觉文章有用,可扫码捐赠本站!(If the article useful, you can scan the QR code to donate))
- Author: shisekong
- Link: https://blog.361way.com/python-getattr/5008.html
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.