from eval to getattr hasattr setattr

现实中的问题:我手中有一个列表[(‘请求网页’,‘网页1’),(‘解析网页’,‘网页1’, (‘保存网页’, ‘网页1’),‘请求网页’,‘网页2’),(‘解析网页’,‘网页2’, (‘保存网页’, ‘网页2’),… ],想将列表中的事情从头到尾都干一遍。

  1. 首先,定义一个类
class Spider:
    def request(self, page):
        print('请求网页:', page)
    def parse(self, page):
        print('解析网页:', page)
    def save(self, page):
        print('保存网页:', page)
  1. 然后我们想的是,如何复用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
  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
  1. 对于函数调用怎么办?
    我们可以使用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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值