进一步探究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中实现结构相似的函数调用方法
Mar 10 Python
关于Python面向对象编程的知识点总结
Feb 14 Python
python3+PyQt5实现自定义分数滑块部件
Apr 24 Python
python面向对象多线程爬虫爬取搜狐页面的实例代码
May 31 Python
Python2.7环境Flask框架安装简明教程【已测试】
Jul 13 Python
Python实现基于POS算法的区块链
Aug 07 Python
浅谈Python中的全局锁(GIL)问题
Jan 11 Python
在linux下实现 python 监控usb设备信号
Jul 03 Python
Flask框架搭建虚拟环境的步骤分析
Dec 21 Python
Windows+Anaconda3+PyTorch+PyCharm的安装教程图文详解
Apr 03 Python
Python 使用Opencv实现目标检测与识别的示例代码
Sep 08 Python
安装pytorch时报sslerror错误的解决方案
May 17 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
超神学院:鹤熙已踏入神圣领域,实力不比凯莎弱
2020/03/02 国漫
关于UEditor编辑器远程图片上传失败的解决办法
2012/08/31 PHP
php之static静态属性与静态方法实例分析
2015/07/30 PHP
通过修改Laravel Auth使用salt和password进行认证用户详解
2017/08/17 PHP
使用PHPWord生成word文档的方法详解
2019/06/06 PHP
通过PHP实现用户注册后邮箱验证激活
2020/11/10 PHP
Javascript YUI 读码日记之 YAHOO.util.Dom - Part.2 0
2008/03/22 Javascript
javascript动态加载三
2012/08/22 Javascript
深入解析contentWindow, contentDocument
2013/07/04 Javascript
JQuery判断HTML元素是否存在的两种解决方法
2013/12/26 Javascript
jquery让指定的元素闪烁显示的方法
2015/03/17 Javascript
AngularJS基础教程之简单介绍
2015/09/27 Javascript
整理Javascript基础语法学习笔记
2015/11/29 Javascript
详解bootstrap用dropdown-menu实现上下文菜单
2017/09/22 Javascript
基于vue-cli npm run build之后vendor.js文件过大的解决方法
2018/09/27 Javascript
vue里如何主动销毁keep-alive缓存的组件
2019/03/21 Javascript
Vue 利用指令实现禁止反复发送请求的两种方法
2019/09/15 Javascript
Python的Scrapy爬虫框架简单学习笔记
2016/01/20 Python
python常见的格式化输出小结
2016/12/15 Python
python自动发送测试报告邮件功能的实现
2019/01/22 Python
Django框架文件上传与自定义图片上传路径、上传文件名操作分析
2019/05/10 Python
详解Python绘图Turtle库
2019/10/12 Python
解析Python 偏函数用法全方位实现
2020/06/26 Python
Python3 ffmpeg视频转换工具使用方法解析
2020/08/10 Python
socket.io 和canvas 实现的共享画板功能
2019/05/22 HTML / CSS
世界上最大的艺术社区:SAA
2020/12/30 全球购物
车辆安全检查制度
2014/01/12 职场文书
黄河象教学反思
2014/02/10 职场文书
四年级评语大全
2014/04/21 职场文书
大学生村官座谈会发言材料
2014/05/25 职场文书
建设幸福中国演讲稿
2014/09/11 职场文书
出售房屋协议书范本
2014/10/06 职场文书
民事和解协议书格式
2014/11/29 职场文书
小学新教师个人总结
2015/02/05 职场文书
校运会通讯稿
2015/07/18 职场文书
Python获取指定日期是"星期几"的6种方法
2022/03/13 Python