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

2017-08-21 21:25:54 +08:00
 saximi

第一个装饰器的代码:

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__方法却被执行了?

2426 次点击
所在节点    Python
17 条回复
Kilerd
2017-08-21 22:17:58 +08:00
def a():
def b():
print("emmmmmmm")
print("oh yep")

a()

为什么 b 没有被执行?
Trim21
2017-08-21 22:20:04 +08:00
楼主发下一个帖子前记得看看 markdown...看一眼预览再发帖...
saximi
2017-08-21 22:26:35 +08:00
@Trim21 我是看过预览才发的,我用论坛用不太好,比如 name 前后各有两个下划线没有显示出来,因为着急问问题,想着这不影响整体阅读就没有去改了
saximi
2017-08-21 22:32:24 +08:00
@Kilerd 不是很明白,您的例子中因为没有 b()这样的调用语句,自然 b 不会被执行。可我的例子中第一个装饰器是执行了 register(f1()),这时 register.__init__()应该被执行的吧?
saximi
2017-08-21 22:37:05 +08:00
@Kilerd 感谢指点,我晕了,register 是函数不是类!顺便问个问题,所谓的函数装饰器,是说装饰器是一个函数,还是说被装饰的对象是函数呢?
enomine
2017-08-21 23:23:10 +08:00
函数装饰器 这只是个中文词汇,有歧义,所以不用太在意。
你只需要知道装饰器可以是一个类也可以是一个函数,被装饰的可以使一个类也可以是一个函数
这边有我总结的装饰器相关的两篇文章,希望可以帮到你。
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
2017-08-21 23:29:35 +08:00
lrxiao
2017-08-21 23:40:04 +08:00
decorator 只是个 AOP 的糖(
saximi
2017-08-21 23:46:02 +08:00
@lrxiao AOP 是什么的缩写呢?语法?
saximi
2017-08-21 23:48:54 +08:00
@enomine 感谢指点,关于装饰器我另外还发了一个问题求指点,如果有空的话,能否看看我发的帖子,点拨我一下呢,谢谢了! https://www.v2ex.com/t/384418#reply2
saximi
2017-08-21 23:49:33 +08:00
@garfieldWu 感谢!
lxml
2017-08-22 01:45:08 +08:00
@saximi #9 面向切面编程
lovestudykid
2017-08-22 07:30:39 +08:00
@enomine 谢谢你的总结,我看了一下,似乎有点问题。你的被装饰的类似乎没必要重载__new__方法吧,如果要的话,应该使用新式类 class A(object),否则__new__不会被调用。
enomine
2017-08-22 10:27:54 +08:00
@lovestudykid 首先,我的代码是 Python3 代码,不存在新式类和旧式类之分,不管怎么声明,都是新式类。其次,我重载__new__方法是来看调用顺序,没别的用处。
saximi
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
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
2017-08-28 19:56:31 +08:00
@saximi
统一回复,装饰器的目的是利用语法糖,以不改变原有函数的功能为原则,额外增加一些逻辑。
你的这两个问题,执行一下代码,你自己就会明白。建议你按照你自己的想法,修改我的代码,看出来的结果区别在哪里,这样就会明白为什么要那样写。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/384675

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX