首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python 学习手册
Python Cookbook
Python 基础教程
Python Sites
PyPI - Python Package Index
http://www.simple-is-better.com/
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
V2EX  ›  Python

Python 新手提问:关于装饰器

  •  
  •   Eyon · 351 天前 · 2280 次点击
    这是一个创建于 351 天前的主题,其中的信息可能已经有所发展或是发生改变。

    之前就对装饰器一知半解,看教程到协程部分,更晕了。我要提的问题是:

    两层结构的装饰器,作用只是为了包函数的参数吗?

    比如样例

    
    def log(func):
        def wrapper(*args, **kw):
            print('call %s():' % func.__name__)
            return func(*args, **kw)
        return wrapper
        
    

    如果函数没有参数,或者说装饰器不需要使用到函数的参数,那么按照下面这样写有什么问题:

    def log(func):
        print('call func: %s' %func.__name__)
        return func
    
    
    
    @log
    def fn(a,b):
        print(a + b)
    
    
    fn(1,2)
    
    20 回复  |  直到 2018-06-07 21:46:21 +08:00
        1
    HelloAmadeus   351 天前 via Android   ♥ 1
    你把装饰器当普通函数用一下,你就明白了。装饰器和普通函数唯一的区别就是装饰器函数会在导入时运行,你实际运行被装饰器装饰的函数是装饰器返回的函数。至于装饰器作用,就是一个语法糖,想怎么用就怎么用,你秉持一个理念,函数可以作为函数的参数,那装饰器在你眼里就是一个普通函数了,普通函数能做什么,装饰器就能做什么。想找一些灵感,可以看看 Python cook book 的装饰器章节
        2
    ipwx   351 天前 via iPhone
    你这代码没问题。另,还可以有三层的
        3
    Kilerd   351 天前
    @log
    def fn():
    ....pass

    实际上只是一个语法糖,他相当于一下代码

    def fn():
    ....pass

    fn = log(fn)
        4
    HelloAmadeus   351 天前 via Android
    你这样用,下次运行 fn,就不会显示 log 了
        5
    chroming   351 天前
    你的写法并没有改变 fn,装饰器的作用是将原函数名指向一个新函数,你这样包了一层仍然是原函数
        6
    enenaaa   351 天前
    第 2 个例子中 wrapper 不能少。
    装饰器就是专门返回 wrapper 的。
        7
    Bramblex2   351 天前
    你需要了解一个基本概念——“高阶函数”,然后一切问题就迎刃而解了
        8
    jatsz   351 天前   ♥ 3
    1,你这样没毛病。
    2,你这样写,比如在函数执行完成后加 log 了,比如你想记录一个函数执行时间的装饰器,你这样写就不行了,而示例中就可以。
    3,还有更复杂的是装饰器本身有参数。

    以前写过装饰器的文章: https://www.imzjy.com/blog/2012-05-23-python-decorator
    4.2 就是三层嵌套的,用来解决装饰器本身有参数的情况。
        9
    Eyon   351 天前
    @HelloAmadeus

    >你实际运行被装饰器装饰的函数是装饰器返回的函数。


    @chroming

    >装饰器的作用是将原函数名指向一个新函数,你这样包了一层仍然是原函数

    谢谢!

    那么,也就是说可以理解成装饰器返回新函数,而这个新函数返回的是老函数?

    比如:

    ```

    def log(func):
    def wraped_func(*args,**kw):
    print('do sth...')
    return func(*args,**kw)
    return wraped_func


    @log
    def fn(a,b):
    print(a + b)


    fn(1,2)

    ```
        10
    neoblackcap   351 天前
    @Eyon 你若是要深挖这个,也可以搜索高级函数以及柯里化(currying)
        11
    gleymonkey   351 天前
    函数作为参数,函数作为返回值。
        12
    nasmatic   351 天前
    你如果这么写没有返回 wrapper:
    def log(func):
    print('call func: %s' %func.__name__)
    return func

    那么假设你装饰一个无参函数,比如这样定义的:
    def fn():
    print('call func: %s' %func.__name__)
        13
    nasmatic   351 天前
    你如果这么写没有返回 wrapper:
    def log(func):
    print('call func: %s' %func.__name__)
    return func

    那么假设你装饰一个无参函数,比如这样定义的:
    def fn():
    print "hello"

    你最后想执行函数时用 fn()这种形式肯定报错
        14
    ech0x   351 天前 via iPhone
    主要你对函数是一等公民这个概念没有理清,你试着写几个函数,它的参数是函数并且返回值也是函数就明白了。
        15
    dengshuang   351 天前
    5 楼和 6 楼都说的不错,装饰器是要返回一个新的函数的。
    你自己的写法,也能在执行时显示结果,但是不能调用它,这和解释器有关了。。。
    装饰器是要返回一个新的函数的
    装饰器是要返回一个新的函数的
    装饰器是要返回一个新的函数的
        16
    whoami9894   351 天前 via Android
    装饰器是一个闭包函数写成 @形式的语法糖
        17
    Linxing   351 天前
    @jatsz #8 手动感谢下 看了你的写法明白了
        18
    qwertyegg   350 天前
    @Bramblex2 一个函数的函数为什么要取这么奇怪的名字,我看廖雪峰老师的教程里面也用这个名字。明明已经存在现有的一个命名:泛函
        19
    Bramblex2   350 天前
    @qwertyegg

    你问问人家数学家为啥要取这个名字啊—— high-order function。

    并且高阶函数跟泛函还是有区别的,泛函往往是空间(函数)对是实数域的映射,而高阶函数是空间(函数)对空间(函数)的映射,所以名字有区别也没没毛病吧。
        20
    qwertyegg   350 天前
    @Bramblex2 有道理,我的理解肤浅了
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4132 人在线   最高记录 5043   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 22ms · UTC 03:22 · PVG 11:22 · LAX 20:22 · JFK 23:22
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1