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
saximi
V2EX  ›  Python

关于装饰器中__init__方法的问题

  •  1
     
  •   saximi · 2017-08-21 21:25:54 +08:00 · 2564 次点击
    这是一个创建于 2650 天前的主题,其中的信息可能已经有所发展或是发生改变。

    第一个装饰器的代码:

    registry = []

    def register(func):

        def __init__(self): 
    
            print("INIT!!!") 
    
        print('running register(%s)' % func)   
    
        registry.append(func)   
    
        return func   
    

    @register

    def f1():

        print('running f1()') 
    

    def main():

        print('registry ->', registry) 
    
        f1()  
    

    if name =='main':

        main()             
    

    上面代码的输出如下,可见装饰器的__init__方法并没有执行:

    running register()

    registry -> []

    running f1()

    第二个装饰器的代码:

    class tracer(object):

        def __init__(self, func):   
    
                print("tracer: init")  
    
                self.func = func 
    
        def __call__(self, *args, **kwargs):    
    
                return self.func(*args, **kwargs) 
    

    class C:

        def __init__(self): 
    
                pass 
    
        @tracer 
    
        def f(self):  
    
                print("run f!") 
    

    print("--------------")

    输出如下:

    tracer: init


    我的问题是,这两个装饰器为何第一个装饰器的__init__方法没有执行,而第二个装饰器的__init__方法却被执行了?

    17 条回复    2017-08-28 19:56:31 +08:00
    Kilerd
        1
    Kilerd  
       2017-08-21 22:17:58 +08:00 via iPhone
    def a():
    def b():
    print("emmmmmmm")
    print("oh yep")

    a()

    为什么 b 没有被执行?
    Trim21
        2
    Trim21  
       2017-08-21 22:20:04 +08:00
    楼主发下一个帖子前记得看看 markdown...看一眼预览再发帖...
    saximi
        3
    saximi  
    OP
       2017-08-21 22:26:35 +08:00
    @Trim21 我是看过预览才发的,我用论坛用不太好,比如 name 前后各有两个下划线没有显示出来,因为着急问问题,想着这不影响整体阅读就没有去改了
    saximi
        4
    saximi  
    OP
       2017-08-21 22:32:24 +08:00
    @Kilerd 不是很明白,您的例子中因为没有 b()这样的调用语句,自然 b 不会被执行。可我的例子中第一个装饰器是执行了 register(f1()),这时 register.__init__()应该被执行的吧?
    saximi
        5
    saximi  
    OP
       2017-08-21 22:37:05 +08:00
    @Kilerd 感谢指点,我晕了,register 是函数不是类!顺便问个问题,所谓的函数装饰器,是说装饰器是一个函数,还是说被装饰的对象是函数呢?
    enomine
        6
    enomine  
       2017-08-21 23:23:10 +08:00   ❤️ 1
    函数装饰器 这只是个中文词汇,有歧义,所以不用太在意。
    你只需要知道装饰器可以是一个类也可以是一个函数,被装饰的可以使一个类也可以是一个函数
    这边有我总结的装饰器相关的两篇文章,希望可以帮到你。
    http://45.32.54.6/2017/04/17/Decorators-for-Class
    http://45.32.54.6/2017/04/17/Decorators-for-Functions-and-Methods
    garfieldWu
        7
    garfieldWu  
       2017-08-21 23:29:35 +08:00
    lrxiao
        8
    lrxiao  
       2017-08-21 23:40:04 +08:00
    decorator 只是个 AOP 的糖(
    saximi
        9
    saximi  
    OP
       2017-08-21 23:46:02 +08:00
    @lrxiao AOP 是什么的缩写呢?语法?
    saximi
        10
    saximi  
    OP
       2017-08-21 23:48:54 +08:00
    @enomine 感谢指点,关于装饰器我另外还发了一个问题求指点,如果有空的话,能否看看我发的帖子,点拨我一下呢,谢谢了! https://www.v2ex.com/t/384418#reply2
    saximi
        11
    saximi  
    OP
       2017-08-21 23:49:33 +08:00
    @garfieldWu 感谢!
    lxml
        12
    lxml  
       2017-08-22 01:45:08 +08:00
    @saximi #9 面向切面编程
    lovestudykid
        13
    lovestudykid  
       2017-08-22 07:30:39 +08:00
    @enomine 谢谢你的总结,我看了一下,似乎有点问题。你的被装饰的类似乎没必要重载__new__方法吧,如果要的话,应该使用新式类 class A(object),否则__new__不会被调用。
    enomine
        14
    enomine  
       2017-08-22 10:27:54 +08:00
    @lovestudykid 首先,我的代码是 Python3 代码,不存在新式类和旧式类之分,不管怎么声明,都是新式类。其次,我重载__new__方法是来看调用顺序,没别的用处。
    saximi
        15
    saximi  
    OP
       2017-08-22 21:11:27 +08:00
    @enomine 关于您写的这篇文章 http://45.32.54.6/2017/04/17/Decorators-for-Functions-and-Methods/。
    我看“ 2.1 函数不带参数”小节中,装饰器的效果等同于 echo()=Decorator.__call__() ,所以等号的右边,即 Decorator.__call__()运行后应该要返回一个函数才对吧?
    但是为何__call__方法直接就执行 self.fun(),而不是 return self.fun 呢?
    saximi
        16
    saximi  
    OP
       2017-08-23 22:51:23 +08:00
    @enomine 关于您的类的装饰器这篇 http://45.32.54.6/2017/04/17/Decorators-for-Class/,
    例子“ 1.3 装饰器带参数 2 ”,既然 A() = Decorator(1,2).__call__() ,那为何__call__方法不返回一个对象,而是返回方法 wrapper,这样等号两边的对象不会不匹配么?
    enomine
        17
    enomine  
       2017-08-28 19:56:31 +08:00
    @saximi
    统一回复,装饰器的目的是利用语法糖,以不改变原有函数的功能为原则,额外增加一些逻辑。
    你的这两个问题,执行一下代码,你自己就会明白。建议你按照你自己的想法,修改我的代码,看出来的结果区别在哪里,这样就会明白为什么要那样写。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2792 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 14:12 · PVG 22:12 · LAX 06:12 · JFK 09:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.