[python]在场景中理解装饰器

原来我也自己通过查资料,来学习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也是同样。

 1 def func_top(url):
 2     data_dict= {}
 3
 4     #在页面上获取到子url
 5     sub_urls = xxxx
 6
 7     data_list = []
 8     for it in sub_urls:
 9         data_list.append(func_sub(it))
10
11     data_dict[‘data‘] = data_list
12
13     return data_dict
14
15 def func_sub(url):
16     data_dict= {}
17
18     #在页面上获取到子url
19     bottom_urls = xxxx
20
21     data_list = []
22     for it in bottom_urls:
23         data_list.append(func_bottom(it))
24
25     data_dict[‘data‘] = data_list
26
27     return data_dict
28
29 def func_bottom(url):
30     #获取数据
31     data = xxxx
32     return data

所以实现方案也就有了:
定义一个装饰器,如果之前取到数据,就直接取cache(file_path)的数据;如果之前没有取到,那么就从网站拉取,并且存入cache中.

 1 import os
 2 import hashlib
 3
 4 def deco_args_recent_cache(category=‘dumps‘):
 5     ‘‘‘
 6     装饰器,返回最新cache的数据
 7     ‘‘‘
 8     def deco_recent_cache(func):
 9         def func_wrapper(*args, **kargs):
10             sig = _mk_cache_sig(*args, **kargs)
11             data = _get_recent_cache(category, func.__name__, sig)
12             if data is not None:
13                 return data
14
15             data = func(*args, **kargs)
16             if data is not None:
17                 _set_recent_cache(category, func.__name__, sig, data)
18             return data
19
20         return func_wrapper
21
22     return deco_recent_cache
23
24 def _mk_cache_sig(*args, **kargs):
25     ‘‘‘
26     通过传入参数,生成唯一标识
27     ‘‘‘
28     src_data = repr(args) + repr(kargs)
29     m = hashlib.md5(src_data)
30     sig = m.hexdigest()
31     return sig
32
33 def _get_recent_cache(category, func_name, sig):
34     full_file_path = ‘%s/%s/%s‘ % (category, func_name, sig)
35     if os.path.isfile(full_file_path):
36         return eval(file(full_file_path,‘r‘).read())
37     else:
38         return None
39
40 def _set_recent_cache(category, func_name, sig, data):
41     full_dir_path = ‘%s/%s‘ % (category, func_name)
42     if not os.path.isdir(full_dir_path):
43         os.makedirs(full_dir_path)
44
45     full_file_path = ‘%s/%s/%s‘ % (category, func_name, sig)
46     f = file(full_file_path, ‘w+‘)
47     f.write(repr(data))
48     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

时间: 2024-10-15 04:35:10

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

Python 基础之八步理解装饰器

装饰器装饰器:在不改变原有代码的情况下,为该原函数扩展新功能特征:返回信函数,替换旧函数语法:@ 语法糖#(1) 装饰器原型#例1: def kuozhan(func):    def newfunc():        print("吃饭前,无精打采")        func()        print("吃饭后,精神百倍")    return newfuncdef func():    print("我是个吃货")#手动的 把新函数 赋

理解Python中的装饰器

文章先由stackoverflow上面的一个问题引起吧,如果使用如下的代码: @makebold @makeitalic def say(): return "Hello" 打印出如下的输出: <b><i>Hello<i></b> 你会怎么做?最后给出的答案是: def makebold(fn): def wrapped(): return "<b>" + fn() + "</b>&q

如何理解python中的装饰器, 这篇文章就够了!

1. python中的函数 理解裝飾器之前先要理解閉包, python中閉包的出現是因爲函數在python中也是一個對象, 也可以被引用, 然後調用, 比如 def log(): print('我是一些log信息') if __name__ == '__main__': print(type(log)) log_func = log log_func() 執行結果如下 <class 'function'> 我是一些log信息 可以看到log函數是一個對象, 可以被賦值給log_func, lo

@修饰符--python中的装饰器

http://blog.csdn.net/shangzhihaohao/article/details/6928808 装饰器模式可以在不影响其他对象的情况下,以动态.透明的方式给单个对象添加职责,也能够处理那些可以撤销的职责.经常用于日志记录.性能测试等场合. 想象一下这个很常见的场景,你写了一个方法只提供给以登陆的用户访问(事实上我也是通过django的@login_required才了解到@修饰符的),你可以写以下代码: 这当然没什么问题,但是你又写了一个方法B,也要求只有登录用户可以访问

Python之简单理解装饰器(1)

装饰器是Python高级应用的一部分,其应用也很广泛.网上对其介绍和讲解也是五花八门,我在这里就对其进行简单介绍,并对如何渐进理解使用装饰器进行说明,以便和大家共同学习.如有更高见解,也请大家留言指正. 装饰器概念简单理解 循序渐进装饰器 装饰器概念简单理解 装饰器按照我的理解,就是在不改变原有函数代码的情况下,对原有函数进行功能的扩展. 这里先写个简单的装饰器,给大家有个概念性的认识. def anotherone(func):  #定义装饰器     def inner():        

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

hello大家好~~我是稀里糊涂林老冷,一天天稀里糊涂的. 前一段时间学习了装饰器,觉着这东西好高大上哇靠!!哈哈,一定要总结一下,方便以后自己查阅,也希望帮助其他伙伴们共同进步! 装饰器: 大家可以这样理解,装饰器是运用闭包的基本原理,对一个目标函数进行装饰.即是在执行一个目标函数之前.之后执行一些特定的事情. 学习装饰器一定要有闭包的基础知识,如果对闭包不是特别理解的话,可以参考我之前的博文http://www.cnblogs.com/Lin-Yi/p/7305364.html,也可以学习其

python入门(六)装饰器的理解

装饰器用于拓展原有函数功能的一种函数比如: def helloWorld(fun) def out() print ("======start========") fun() print ("=====end======") return out @helloWorld def back () print ("let's go") back() 运行结果: ======start======== let's go =====end====== b

Python 中的装饰器

说到装饰器是我们每个学Python人中的心痛. 装饰器作用:是用来装饰其他函数的,为其他函数添加新功能. 原则:1.不能改变被修饰函数的源代码. 2.不能修改被修饰函数的调用方式. 学装饰器前还需要了解的东西: 返回值(return): return 语句是可选的,它可以定义在函数体的任意位置表示函数调用到此结束.如果没有return语句输出的是none,如果有return语句但是return后没有跟东西,也是返回的是none. 注意:(1)要想看到return后边的值,需要打印出来print(

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

Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下--比如测试时--会导致一些问题.Python 通过 functool.wraps 为我们解决了这个问题:在编写装饰器时,在实现前加入 @functools.wraps(func) 可以保证装饰器不会对被装饰函数造成影响.比如,在 Flask 中,我们要自己重写 login_required 装饰器,但不想影响被装饰器装饰的方法,则 login_req