V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
linkbg
V2EX  ›  Python

关于 python 装饰器的理解请教一下大家

  •  
  •   linkbg · 2016-02-25 09:58:54 +08:00 · 3744 次点击
    这是一个创建于 3203 天前的主题,其中的信息可能已经有所发展或是发生改变。

    python 的装饰器,我查了相关的资料,意思就是一个函数可以传入另一个函数中。
    那么我可不可以不是特别规范的理解为这是一种函数中的继承呢?或者是类似继承的形式在函数中的实现呢?谢谢

    32 条回复    2016-03-02 14:39:54 +08:00
    sudoz
        1
    sudoz  
       2016-02-25 10:04:24 +08:00
    显然不是继承,继承是可以重载父类的属性
    而装饰器就是字面理解,在方法外面再包一层而无法对被包裹的方法进行改动
    strahe
        2
    strahe  
       2016-02-25 10:06:08 +08:00
    不能这么理解吧 不是一回事
    SlipStupig
        3
    SlipStupig  
       2016-02-25 10:07:40 +08:00
    这个理解是不对的!就是在调用某个函数之前先调用装饰器函数, python 函数等于是个毛坯房装饰器等于一个毛坯房多了一盏灯,灯能干嘛不用我说了吧
    ChiangDi
        4
    ChiangDi  
       2016-02-25 10:13:07 +08:00 via Android
    一个函数传到另一个函数那叫高阶函数啊
    WangYanjie
        5
    WangYanjie  
       2016-02-25 10:13:56 +08:00
    我觉得不是这个样子的。

    我觉得 Python 的装饰器本质上是一颗语法糖,
    利用的是 Python 中函数可以作为参数传递的特点,
    实现的是在执行函数时,做一些额外功能的任务。

    @dec1
    @dec2
    def func():
    pass



    def func():
    pass
    func = dec1(dec2(func))

    不是等价的嘛
    jixiangqd
        6
    jixiangqd  
       2016-02-25 10:30:11 +08:00
    @WangYanjie 很明显不等价好么。。。不要在这误导。。。。

    装饰器就是装饰器,可以参考 decorator pattern 的相关介绍。

    装饰器和继承也不等价。不要钻牛角尖,非要把它理解多透彻,多用就知道怎么回事了。
    xAx
        7
    xAx  
       2016-02-25 10:35:59 +08:00
    不用 python 路过,只想说 GOF23 你肯定一点没看
    julyclyde
        8
    julyclyde  
       2016-02-25 10:40:23 +08:00
    不是继承,是同名替换,具体行为在装饰器里
    chenxytw
        9
    chenxytw  
       2016-02-25 10:45:17 +08:00
    bramblex
        10
    bramblex  
       2016-02-25 10:47:18 +08:00
    不过就是一个高阶函数在 python 里的语法糖而已 ╮(╯▽╰)╭

    把一个函数包装成另一个函数的函数。
    mulog
        11
    mulog  
       2016-02-25 10:48:55 +08:00
    @jixiangqd 本来就是等价的啊
    https://www.python.org/dev/peps/pep-0318/


    Current Syntax
    The current syntax for function decorators as implemented in Python 2.4a2 is:

    @dec2
    @dec1
    def func(arg1, arg2, ...):
    pass

    This is equivalent to:

    def func(arg1, arg2, ...):
    pass
    func = dec2(dec1(func))

    without the intermediate assignment to the variable func . The decorators are near the function declaration. The @ sign makes it clear that something new is going on here.
    herozem
        12
    herozem  
       2016-02-25 10:49:52 +08:00
    装饰器就是语法糖,

    @bar
    def foo():
    pass

    就相当与:

    foo = bar(foo),

    在这里 foo 就不是之前的 foo 了, foo 变成了 bar 里面返回的东西,如果返回函数,那 foo 还是函数,如果返回字符串,那 foo 就是字符串:

    >>> def bar(func):
    ... return "hi"
    ...
    >>> @bar
    ... def foo():
    ... pass
    ...
    >>> foo
    'hi'

    https://github.com/jiajunhuang/blog/blob/master/python_descriptor_and_decorator.rst 我自己写的总结,不知道对你有没有帮助
    jixiangqd
        13
    jixiangqd  
       2016-02-25 11:12:36 +08:00
    @chenxytw
    @mulog
    @WangYanjie

    Sorry ,眼花看错了。。。恩,是等价的。。。
    limbo0
        14
    limbo0  
       2016-02-25 11:37:58 +08:00
    需要了解两个概念 闭包和函数引用
    julyclyde
        15
    julyclyde  
       2016-02-25 12:00:22 +08:00
    @limbo0 你因果倒置了。实现闭包需要用装饰器,但装饰器本身很单纯
    wellsc
        16
    wellsc  
       2016-02-25 12:35:02 +08:00
    花式闭包
    hahastudio
        17
    hahastudio  
       2016-02-25 12:42:28 +08:00
    s-m-n theorem
    limbo0
        18
    limbo0  
       2016-02-25 12:44:24 +08:00
    @julyclyde 额, 是你弄错了吧? 闭包完全不依赖装饰器,
    闭包 = 在函数里定义函数
    python 装饰器 = 闭包 + 语法糖
    lxy
        19
    lxy  
       2016-02-25 12:58:33 +08:00
    其实就是用函数来封装函数。用惯之后特别爽,写个循环都能用上装饰器~
    shyling
        20
    shyling  
       2016-02-25 13:04:07 +08:00
    装饰器就是高阶函数的一个语法糖嘛=.=
    Allianzcortex
        21
    Allianzcortex  
       2016-02-25 13:04:10 +08:00
    语法糖

    最好的理解就是在 django 和 Flask 里都有一个  @login_required,如果有任何需要登陆后才能操作的函数,在前面加上一个 @login_required()
    shyling
        22
    shyling  
       2016-02-25 13:08:15 +08:00
    对了...decorator 不是闭包.你能在 decorator 装饰的函数里访问 decorator 里的局部变量?
    youkochan
        23
    youkochan  
       2016-02-25 13:18:19 +08:00
    应该叫复合函数?
    MrEggNoodle
        24
    MrEggNoodle  
       2016-02-25 13:20:48 +08:00
    找一本叫作《 python 学习手册》的书,我的答案就在里面找到的。我想你的答案也在里面。
    julyclyde
        25
    julyclyde  
       2016-02-25 13:24:31 +08:00
    @limbo0 装饰器那一层可以不包含被内部函数引用的变量,所以也可以不形成闭包
    julyclyde
        26
    julyclyde  
       2016-02-25 13:25:08 +08:00
    @limbo0 你首先应该区分“可以做”和“必须做”以及“做了之后的附带效应”这三个概念
    limbo0
        27
    limbo0  
       2016-02-25 13:58:52 +08:00
    @julyclyde 刚看了下确实是我弄混了, 一般用的时候都是有参数用的, 那为什么说'实现闭包需要用装饰器'
    shuax
        28
    shuax  
       2016-02-25 14:03:48 +08:00
    @jixiangqd 难道不等价?我的 python 白学了。
    incompatible
        29
    incompatible  
       2016-02-25 14:09:47 +08:00 via iPhone
    搞 Java 的进来说一声:
    这不是语法糖,跟设计模式里的 Decorator 也没什么关系。
    这玩意儿就是用来实现 AOP 的。 21 楼的 @Allianzcortex 已经把它的用法说的很明白了。
    feather12315
        30
    feather12315  
       2016-02-25 15:40:29 +08:00 via Android
    同意 17 楼答案,花式闭包。
    前几天刚好写过相关
    [闭包与装饰器]( https://vvl.me/style/2016/02/17/python%E4%B9%8B%E9%97%AD%E5%8C%85%E4%B8%8E%E8%A3%85%E9%A5%B0%E5%99%A8.html)

    装饰器是用来装饰函数的;它返回的是一个函数对象;被装饰函数的标识符指向返回函数的对象;语法糖 @deco


    若是还不明白的话,参考资料里面有慕课网的超链接。
    startover
        31
    startover  
       2016-02-25 21:53:40 +08:00   ❤️ 1
    如果一个函数被调用时需要增加一些功能,要么重写这个函数,要么利用高阶函数传入这个函数然后在高阶函数内部改造最后返回一个新的函数。后一种方法,即装饰器。

    归根结底,装饰器就是利用了高阶函数和闭包的特性实现的语法糖,个人认为不用执着于概念,知道其应用场景就好了。

    可以参考我之前写的一篇文章: http://startover.github.io/articles/2015/04/27/python-decorator-mistake/
    wdg8106
        32
    wdg8106  
       2016-03-02 14:39:54 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5006 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 04:00 · PVG 12:00 · LAX 20:00 · JFK 23:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.