进一步探究Python的装饰器的运用


Posted in Python onMay 05, 2015

装饰器在 python 中用的相当广泛,如果你用过 python 的一些 web 框架,那么一定对其中的 “ route() 装饰器” 不陌生,今天咱们再看一个具体的案例。

咱们来模拟一个场景,需要你去抓去一个页面,然后这个页面有好多url也要分别去抓取,而进入这些子url后,还有数据要抓取。简单点,我们就按照三层来看,那我们的代码就是如下:
 

def func_top(url):
  data_dict= {}
 
  #在页面上获取到子url
  sub_urls = xxxx
 
  data_list = []
  for it in sub_urls:
    data_list.append(func_sub(it))
 
  data_dict['data'] = data_list
 
  return data_dict
 
def func_sub(url):
  data_dict= {}
 
  #在页面上获取到子url
  bottom_urls = xxxx
 
  data_list = []
  for it in bottom_urls:
    data_list.append(func_bottom(it))
 
  data_dict['data'] = data_list
 
  return data_dict
 
def func_bottom(url):
  #获取数据
  data = xxxx
  return data

func_top是上层页面的处理函数,func_sub是子页面的处理函数,func_bottom是最深层页面的处理函数,func_top会在取到子页面url后遍历调用func_sub,func_sub也是同样。
如果正常情况下,这样确实已经满足需求了,但是偏偏这个你要抓取的网站可能极不稳定,经常链接不上,导致数据拿不到。
于是这个时候你有两个选择:
1.遇到错误就停止,之后重新从断掉的位置开始重新跑
2.遇到错误继续,但是要在之后重新跑一遍,这个时候已经有的数据不希望再去网站拉一次,而只去拉没有取到的数据
对第一种方案基本无法实现,因为如果别人网站的url调整顺序,那么你记录的位置就无效了。那么只有第二种方案,说白了,就是要把已经拿到的数据cache下来,等需要的时候,直接从cache里面取。
OK,目标已经有了,怎么实现呢?
如果是在C++中的,这是个很麻烦的事情,而且写出来的代码必定丑陋无比,然而庆幸的是,我们用的是python,而python对函数有装饰器。
所以实现方案也就有了:
定义一个装饰器,如果之前取到数据,就直接取cache的数据;如果之前没有取到,那么就从网站拉取,并且存入cache中.
代码如下:
 

import os
import hashlib
 
def deco_args_recent_cache(category='dumps'):
  '''
  装饰器,返回最新cache的数据
  '''
  def deco_recent_cache(func):
    def func_wrapper(*args, **kargs):
      sig = _mk_cache_sig(*args, **kargs)
      data = _get_recent_cache(category, func.__name__, sig)
      if data is not None:
        return data
 
      data = func(*args, **kargs)
      if data is not None:
        _set_recent_cache(category, func.__name__, sig, data)
      return data
 
    return func_wrapper
 
  return deco_recent_cache
 
def _mk_cache_sig(*args, **kargs):
  '''
  通过传入参数,生成唯一标识
  '''
  src_data = repr(args) + repr(kargs)
  m = hashlib.md5(src_data)
  sig = m.hexdigest()
  return sig
 
def _get_recent_cache(category, func_name, sig):
  full_file_path = '%s/%s/%s' % (category, func_name, sig)
  if os.path.isfile(full_file_path):
    return eval(file(full_file_path,'r').read())
  else:
    return None
 
def _set_recent_cache(category, func_name, sig, data):
  full_dir_path = '%s/%s' % (category, func_name)
  if not os.path.isdir(full_dir_path):
    os.makedirs(full_dir_path)
 
  full_file_path = '%s/%s/%s' % (category, func_name, sig)
  f = file(full_file_path, 'w+')
  f.write(repr(data))
  f.close()

然后,我们只需要在每个func_top,func_sub,func_bottom都加上deco_args_recent_cache这个装饰器即可~~
搞定!这样做最大的好处在于,因为top,sub,bottom,每一层都会dump数据,所以比如某个sub层数据dump之后,是根本不会走到他所对应的bottom层的,减少了大量的开销!
OK,就这样~ 人生苦短,我用python!

注:

python3 已经原生支持了这种功能!链接如下:

http://docs.python.org/py3k/whatsnew/3.2.html#functools

推荐阅读:

https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize

Python 相关文章推荐
python实现Decorator模式实例代码
Feb 09 Python
python3下实现搜狗AI API的代码示例
Apr 10 Python
Python查找第n个子串的技巧分享
Jun 27 Python
浅谈django三种缓存模式的使用及注意点
Sep 30 Python
用Python PIL实现几个简单的图片特效
Jan 18 Python
Python函数和模块的使用总结
May 20 Python
python画双y轴图像的示例代码
Jul 07 Python
利用 Flask 动态展示 Pyecharts 图表数据方法小结
Sep 04 Python
python进行OpenCV实战之画图(直线、矩形、圆形)
Aug 27 Python
Python CategoricalDtype自定义排序实现原理解析
Sep 11 Python
Python基础之教你怎么在M1系统上使用pandas
May 08 Python
Python实现双向链表基本操作
May 25 Python
Python获取任意xml节点值的方法
May 05 #Python
Python实现方便使用的级联进度信息实例
May 05 #Python
Python封装shell命令实例分析
May 05 #Python
用Python中的字典来处理索引统计的方法
May 05 #Python
python递归计算N!的方法
May 05 #Python
浅谈Python中数据解析
May 05 #Python
探究Python多进程编程下线程之间变量的共享问题
May 05 #Python
You might like
PHP Class&Object -- PHP 自排序二叉树的深入解析
2013/06/25 PHP
PHP 根据key 给二维数组分组
2016/12/09 PHP
JQuery 获取和设置Select选项的代码
2010/02/07 Javascript
prettify 代码高亮着色器google出品
2010/12/28 Javascript
js中top、clientTop、scrollTop、offsetTop的区别 文字详细说明版
2011/01/08 Javascript
JavaScript中的关键字"VAR"使用详解 分享
2013/07/31 Javascript
浅析JS中document对象的一些重要属性
2014/03/06 Javascript
js实现当复选框选择匿名登录时隐藏登录框效果
2015/08/14 Javascript
JavaScript通过使用onerror设置默认图像显示代替alt
2016/03/01 Javascript
js动态生成form 并用ajax方式提交的实现方法
2016/09/09 Javascript
JavaScript基于自定义函数判断变量类型的实现方法
2016/11/23 Javascript
javascript设计模式 ? 原型模式原理与应用实例分析
2020/04/10 Javascript
[00:56]跨越时空加入战场 全新祈求者身心“失落奇艺侍祭”展示
2019/07/20 DOTA
Python 中PyQt5 点击主窗口弹出另一个窗口的实现方法
2019/07/04 Python
处理Selenium3+python3定位鼠标悬停才显示的元素
2019/07/31 Python
基于Python和PyYAML读取yaml配置文件数据
2020/01/13 Python
keras模型可视化,层可视化及kernel可视化实例
2020/01/24 Python
opencv python如何实现图像二值化
2020/02/03 Python
Python使用jupyter notebook查看ipynb文件过程解析
2020/06/02 Python
浅析Python 多行匹配模式
2020/07/24 Python
python 8种必备的gui库
2020/08/27 Python
CSS3 box-sizing属性详解
2016/11/15 HTML / CSS
HTML5离线应用与客户端存储的实现
2018/05/03 HTML / CSS
Timberland德国官网:靴子、鞋子、衣服、夹克及配件
2019/12/10 全球购物
构造方法和其他方法的区别?怎么调用父类的构造方法
2013/09/22 面试题
优秀的教师个人的中文求职信
2013/09/21 职场文书
学校庆元旦歌咏比赛主持词
2014/03/18 职场文书
办公室主任竞聘演讲稿
2014/05/15 职场文书
小学生志愿者活动方案
2014/08/23 职场文书
运动会稿件100字
2014/09/24 职场文书
优秀党员事迹材料
2014/12/18 职场文书
学生党员检讨书范文
2014/12/27 职场文书
酒店财务经理岗位职责
2015/04/08 职场文书
2015年度合同管理工作总结
2015/05/22 职场文书
在校生证明
2015/06/17 职场文书
演讲比赛通讯稿
2015/07/18 职场文书