好吧,我知道是大半夜……,但我还是觉得赶紧花上半个小时,把这最新的想法分享出来是值得的~直接进入正题~

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

func_top是上层页面的处理函数,func_sub是子页面的处理函数,func_bottom是最深层页面的处理函数,func_top会在取到子页面url后遍历调用func_sub,func_sub也是同样。
如果正常情况下,这样确实已经满足需求了,但是偏偏这个你要抓取的网站可能极不稳定,经常链接不上,导致数据拿不到。

于是这个时候你有两个选择:

  • 1.遇到错误就停止,之后重新从断掉的位置开始重新跑
  • 2.遇到错误继续,但是要在之后重新跑一遍,这个时候已经有的数据不希望再去网站拉一次,而只去拉没有取到的数据

对第一种方案基本无法实现,因为如果别人网站的url调整顺序,那么你记录的位置就无效了。那么只有第二种方案,说白了,就是要把已经拿到的数据cache下来,等需要的时候,直接从cache里面取。

OK,目标已经有了,怎么实现呢?
如果是在C++中的,这是个很麻烦的事情,而且写出来的代码必定丑陋无比,然而庆幸的是,我们用的是python,而python对函数有装饰器。

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

代码如下:

然后,我们只需要在每个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

暂无相关产品

21则回应给“python装饰器的一个妙用”

  1. 依云说道:

    嗯,我就喜欢这样的装饰品,所以毫不犹豫地装了 Python 3.2——
    http://docs.python.org/py3k/whatsnew/3.2.html#functools

    [回复]

    依云 回复:

    s/品/器

    [回复]

    Dante 回复:

    python居然原生支持了了,太强了!
    啊,开始纠结是不是要往python3上迁移了。。。

    [回复]

    依云 回复:

    迁移吧,Vim 的 Python3 支持的 bug 我都搞定了,一直都没人测试呢。。。

    [回复]

    Dante 回复:

    唉,django一直不肯支持python3,也是我一直不敢迁移的原因。。

    [回复]

  2. ==说道:

    请问,win 上的 gvim 可以设置 程序半透明 或者 背景图片 吗?谢谢。网上的都是 linux 下在终端中用 vim 并设置终端透明

    [回复]

  3. saalihmao说道:

    对python不是很熟,不过读读代码看上去就是装饰器模式嘛~ 这个所有带有一点函数式味道的语言都可以实现的,c++也是可以的,函数对象+装饰器模式就可以~ 不丑陋的 : )

    [回复]

  4. saalihmao说道:

    大概是这样
    class base
    {
    public:
    int operator()(char* some_para) = 0;
    };

    class deco:public base
    {
    base* pBase;
    public:
    explicit deco(const base* p){…;}

    int operator()(char* some_para)
    {
    //do something

    (*pBase)(some_para);
    ….
    //still do something
    }
    }

    [回复]

  5. saalihmao说道:

    呃 deco类的构造函数参数类型应该把const去掉~ : ) 失误失误

    [回复]

    Dante 回复:

    不过总感觉c++用某些设计模式会比较别扭,包括语法,效率,之类的,之前写bayonet项目时,c++用到状态模式,到处是指针,挺郁闷。。

    还有,博客支持pre标签哦,代码显示会友好一些,留言页面有说明~

    [回复]

    saalihmao 回复:

    c++的面向对象方面确实是这样~~ 一旦用到继承之类的就满天指针,不方便,而且没有GC内存分配的效率也很成问题~~

    不过也不一定非要用对象嘛~ 类型也是可以的,就像这个问题这样可能更好些

    [回复]

    saalihmao 回复:

    呵呵pre标签不支持template …?

    [回复]

    Dante 回复:

    呃,你是说尖括号转义了吗?

    [回复]

    saalihmao 回复:

    嗯= = 尖括号被吃掉了~ 应该怎么写?~

    [回复]

    Dante 回复:

    我试一下

    [回复]

    Dante 回复:

    好像把lang写上就可以了,我写的是cpp类型。

    [回复]

    saalihmao 回复:

    测试下…

    [回复]

    saalihmao 回复:

    还是不行… 换个浏览器

    [回复]

  6. [...] 这篇文章也是说这个问题(http://www.vimer.cn/?p=2124),这个例子更为精炼(http://wiki.python.org/moin/PythonDecoratorLibrary#Memoize) [...]

  7. def _get_recent_cache(category, func_name, sig):这个装饰器有缺陷啊,func_name这个参数还不如去掉。

    [回复]

    Dante 回复:

    对,确实冗余了,以前还不熟悉

    [回复]

发表评论