现实中的问题:我手中有一个列表[(‘请求网页’,‘网页1’),(‘解析网页’,‘网页1’, (‘保存网页’, ‘网页1’),‘请求网页’,‘网页2’),(‘解析网页’,‘网页2’, (‘保存网页’, ‘网页2’),… ],想将列表中的事情从头到尾都干一遍。
- 首先,定义一个类
class Spider:
def request(self, page):
print('请求网页:', page)
def parse(self, page):
print('解析网页:', page)
def save(self, page):
print('保存网页:', page)
- 然后我们想的是,如何复用Spider里的方法
许多人的做法是直接使用eval
做法如下
todo_lst = [('request', 'www.exobrain.online'), ('parse', 'www.exobrain.online'), ('save', 'www.exobrain.online'),('request', 'www.exobrain.online/categories/'), ('parse', 'www.exobrain.online/categories/'), ('save', 'www.exobrain.online/categories/'), ('方法测试1','www.exobrain.online/categories/')]
spider = Spider()
for item in todo_lst:
string = 'spider.' + item[0]+'("'+item[1]+'")'
eval(string)
出来了结果
请求网页: www.exobrain.online
解析网页: www.exobrain.online
保存网页: www.exobrain.online
请求网页: www.exobrain.online/categories/
解析网页: www.exobrain.online/categories/
保存网页: www.exobrain.online/categories/
...
AttributeError: 'Spider' object has no attribute '错误的方法测试1'(报错:部分)
我们看到了报错,自然可以用try except处理。
but,eval is evil, it’s not suggested. If you use eval, python is no longer elegant.
So, we introduce the inbuit methods “getattr, hasattr, setattr”
(参考自https://stackoverflow.com/questions/3061/calling-a-function-of-a-module-by-using-its-name-a-string
不得不感慨国内外的差距,人家11years前解决的问题,我们到现在还有好多程序员处于问题之中,还在大量使用eval()。)
使用getattr代替eval, 将for部分注释掉重写如下
todo_lst = [('request', 'www.exobrain.online'), ('parse', 'www.exobrain.online'), ('save', 'www.exobrain.online'),('request', 'www.exobrain.online/categories/'), ('parse', 'www.exobrain.online/categories/'), ('save', 'www.exobrain.online/categories/'), ('方法测试1','www.exobrain.online/categories/')]
spider = Spider()
# for item in todo_lst:
# string = 'spider.' + item[0]+'("'+item[1]+'")'
# eval(string)
for item in todo_lst:
if not hasattr(spider, item[0]):
print('Spider类里不存在方法:', item[0])
continue
getattr(spider, item[0])(item[1])
我们看到了漂亮的结果,有没有发现上面的hasattr+getattr的代码比eval的代码更加优雅。
I choose getattr instead of eval just because of elegance. ?
请求网页: www.exobrain.online
解析网页: www.exobrain.online
保存网页: www.exobrain.online
请求网页: www.exobrain.online/categories/
解析网页: www.exobrain.online/categories/
保存网页: www.exobrain.online/categories/
Spider类里不存在方法: 方法测试1
- 动态将函数添加到类或者对象里面
def method_added(page):
print('调用method_added函数',page)
# 将method_added 注册到spider对象里
setattr(spider, 'method_added', method_added)
# 测试method_added是否添加到spider对象里
print(hasattr(spider, 'method_added'))
# >True 返回值为True, 添加成功
getattr(spider, 'method_added')('www.exobrain.online')
# > 调用method_added函数 www.exobrain.online
def method_added2(self, page):
print('调用method_added2函数',page)
# 将method_added2 注册到Spider类里
setattr(Spider, 'method_added2', method_added2)
# 测试method_added是否添加到spider对象里
print(hasattr(spider, 'method_added2'))
# >True 返回值为True, 添加成功
getattr(spider, 'method_added2')('www.exobrain.online')
# > 调用method_added函数 www.exobrain.online
- 对于函数调用怎么办?
我们可以使用locals 和 globals。locals() 和 globals() 是python的两个内置函数,通过它们可以一字典的方式访问局部和全局变量。
def foo():
print "foo"
def bar():
print "bar"
func_list = ["foo","bar"]
for func in func_list:
locals()[func]()
# >foo
# >bar
for func in func_list:
globals()[func]()
# >foo
# >bar
参考:
https://stackoverflow.com/questions/3061/calling-a-function-of-a-module-by-using-its-name-a-string