原来我也自己通过查资料,来学习python的装饰器,但是效果不好。因为没有接触过需要用到装饰器的场景,所以

一起的资料都只停留在纸面上,但是今天偶然看到了vimer的这篇文章:http://www.vimer.cn/2011/04/python%E8%A3%85%E9%A5%B0%E5%99%A8%E7%9A%84%E4%B8%80%E4%B8%AA%E5%A6%99%E7%94%A8.html

我们就根据这篇文章的思路来,在场景中理解python装饰器

其中的一个场景是:爬取数据的时候,目标网站,不稳定。爬虫在爬取数据的时候可能异常。

解决方案:

思路:把爬中的每个方法爬取的数据,都存在硬盘中,存储规则如下:

file_path:/method_name/

file_name:MD5_number.txt

解释:MD5_number是通过方法名和传入的参数计算出来的唯一标识符(搜索一下MD5)这样做的好 处,不需要把数据爬下来之后才能判断是否爬过。

最后:如果方法爬取目标url的数据时异常,暂不执行该方法。最后多跑几次这个爬虫脚本就可以了!

该爬虫调用三个方法,设计一个通用的方法:根据每个方法的方法名和传入的参数通过MD5计算出唯一的标识符(MD5_numbe)。然后在file_path目录中查找文件名为MD5_numbe的文件,如果file_path中的没有这个文件,则按照存储规则存储数据。如果找到了,不存储到硬盘中,直接返回data,用于下一个方法。

————————————

场景结束

++++++++++++

在上面描述的这个场景中,修饰器用在什么地方?

对了!就是那个通用方法,就需要用修饰器来实现,为什么?一步步的来

python中一切东西都是对象。方法就可以做当作对象来传递!

1.什么是方法?

传入参数,然后对传入的参数进行一系列操作。

2.什么是高级方法

方法接受的参数是方法,仅此而已。

3.什么是闭包

当方法1里面有一个方法2,方法2调用的是方法1接收到的参数,最后结果返回方法2。提供这种实现的技术叫做闭包。

说到底修饰器就是一个方法,而传入的参数是方法,并在修饰器中对传入的方法进行一系列的操作(这里用到闭包)。从而实现了,在不修改原方法基础上,增加新的操作。比如上一个场景中的,检验有没有重复爬取数据。

爬中脚本中的代码片段

func_top是上层页面的处理函数,func_sub是子页面的处理函数,func_bottom是最深层页面的处理函数,func_top会在取到子页面url后遍历调用func_sub,func_sub也是同样。

 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

所以实现方案也就有了:
定义一个装饰器,如果之前取到数据,就直接取cache(file_path)的数据;如果之前没有取到,那么就从网站拉取,并且存入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这个装饰器即可~~

参考资料:

浅显理解闭包:https://serholiu.com/python-closures

修饰器:http://jnotes.googlecode.com/svn/trunk/Notes/NotesOnPythonLearning/Python_decorator.html

[python]在场景中理解装饰器的更多相关文章

  1. Python 标准库中的装饰器

    题目描述 1.简单举例 Python 标准库中的装饰器 2.说说你用过的 Python 标准库中的装饰器 1. 首先,我们比较熟悉,也是比较常用的 Python 标准库提供的装饰器有:property ...

  2. 理解Python中的装饰器

    文章先由stackoverflow上面的一个问题引起吧,如果使用如下的代码: @makebold @makeitalic def say(): return "Hello" 打印出 ...

  3. 理解Python中的装饰器//这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档

    转自:http://www.cnblogs.com/rollenholt/archive/2012/05/02/2479833.html 这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档 ...

  4. Python(三)对装饰器的理解

    装饰器是 Python 的一个重要部分,也是比较难理解和使用好的部分.下面对装饰器做一下简单整理 1. 前言 装饰器实际上是应用了设计模式里,装饰器模式的思想: 在不概念原有结构的情况下,添加新的功能 ...

  5. 简单说明Python中的装饰器的用法

    简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下   装饰器对与 ...

  6. 浅显易懂的谈一谈python中的装饰器!!

    hello大家好~~我是稀里糊涂林老冷,一天天稀里糊涂的. 前一段时间学习了装饰器,觉着这东西好高大上哇靠!!哈哈,一定要总结一下,方便以后自己查阅,也希望帮助其他伙伴们共同进步! 装饰器: 大家可以 ...

  7. Python类中的装饰器在当前类中的声明与调用

    [本文出自天外归云的博客园] 我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器.代码如下: class Test(): xx = False def __in ...

  8. 【Python】python中的装饰器——@

    对装饰器本来就一知半解的,今天终于弄清楚了,Python中的装饰器是对装饰者模式的很好运用,简化到骨子里了. python中为什么需要装饰器,看这里:http://www.cnblogs.com/hu ...

  9. Python 中实现装饰器时使用 @functools.wraps 的理由

    Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下——比如测试时——会导致一些问题.Python 通过  ...

随机推荐

  1. 模拟storage copy 功能失败的记录

    试验设想: 机器1: alter database begin backup 然后,在oracle仍然活动的状态下,将$ORACLE_BASE目录全部压缩拷贝到机器2 机器2: startup:失败 ...

  2. 实现Android Studio JNI开发C/C++使用__android_log_print输出Log

    相信很多人在刚开始学习Android JNI编程的时候,需要输出Log,在百度Google搜索的时候都是说需要在Android.mk中加入LOCAL_LDLIBS+= -L$(SYSROOT)/usr ...

  3. Codeforces Round #382 (Div. 2)B. Urbanization 贪心

    B. Urbanization 题目链接 http://codeforces.com/contest/735/problem/B 题面 Local authorities have heard a l ...

  4. Swift编程语言中的方法引用

    由于Apple官方的<The Swift Programming Guide>对Swift编程语言中的方法引用介绍得不多,所以这里将更深入.详细地介绍Swift中的方法引用. Swift与 ...

  5. 菜鸟调错(八)—— Maven编译错误:不兼容的类型的解决方案

    泛型在实际的工作中应用非常广泛,关于泛型就不在这里赘述了,感兴趣请戳<重新认识泛型>.项目中用到了如下的泛型: public <T> T query(String sql, R ...

  6. JavaScript跨域方法

    一.什么是跨域 JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象.但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦.这里把涉及到跨域的一些问题简单地整理一下: ...

  7. Freemyapps赚取积分终极图文教程

    Freemyapps怎么赚积分.Clash of Clans宝石获得技巧的终极教程来啦~此教程详细指导大家一步步的成功获取大量积分,买5个农民神马的自然不再话下.当然,人民币玩家可以略过~   原文作 ...

  8. 一些值得学习和借鉴的.Net 开源项目

    1.DotNetFramework .NET Reference Source 发布了 beta 版,可以在线浏览 .NET Framework 4.5.1 的源代码,并且可以通过配置,在 Visua ...

  9. “远程调试监视器(MSVSMON.EXE)似乎没有在远程计算机上运行“的完美解决方案

    今天调试程序时,Visual Studio突然报出了如下错误: Microsoft Visual Studio 远程调试监视器(MSVSMON.EXE)似乎没有在远程计算机上运行.这可能是因为防火墙阻 ...

  10. SSIS:控件清单

    Control Flow 控制流程 Containers 容器 For Loop Container Foreach Loop Container Sequence Container Core Ta ...