为什么Python类方法装饰器不接收方法作为绑定方法?

2 投票
2 回答
717 浏览
提问于 2025-04-17 02:40

当我为一个类的方法创建装饰器时,它总是把这个方法当作“函数”类型来处理。

不过,当我稍微尝试一下其他东西时,我得到的却是绑定的方法:

class Test(object):
    def save(self):
        print "Save called"
    def func(self):
        print "Func called"

然后:

>>> type(Test.func)
<type 'instancemethod'>
>>> type(Test().func)
<type 'instancemethod'>

我最终想做的是创建一个类方法的装饰器,同时也装饰同一个类里的其他方法。我该怎么做呢?

2 个回答

2

这要看事情发生的顺序。

如果你用一个“正常”的方法,接下来会发生以下事情:

class Test(object):
    def save(self):
        print "Save called"
    def func(self):
        print "Func called"

>>> Test.__dict__["func"]
<function func at 0x00B43E30>
>>> Test.func
<unbound method Test.func>

结果应该是一样的。那么这里发生了什么呢?我们来看:

>>> f = Test.__dict__["func"]
>>> m = f.__get__(None, Test)
>>> f, m
(<function func at 0x00B43E30>, <unbound method Test.func>)

第一个是原始的函数对象,第二个是当你真正调用这个方法时创建的方法对象。

另外,如果你有一个实例:

>>> t = Test()
>>> t.func
<bound method Test.func of <__main__.Test object at 0x00B48AB0>>
>>> f.__get__(t, Test)
<bound method Test.func of <__main__.Test object at 0x00B48AB0>>

那么这就是在访问属性时发生的事情。

现在回到你的问题:

之所以会这样,是因为原始函数存在于类的 __dict__ 中。方法对象是在访问时创建的。

3

这是不可能的;你需要使用类装饰器或 metaclass 来实现。装饰器的语法

class Foo(object):
    @dec
    def bar(self): pass

意味着

class Foo(object)
    def bar(self): pass
    bar = dec(bar)

在定义一个 class 时,处理的过程是:先执行类的主体,然后收集所有的定义,并把它们包裹在一个 class 对象里。也就是说,装饰是在 class 还没有被创建出来之前就完成了。

撰写回答