Python中的装饰器、lambda和成员函数调用?

0 投票
1 回答
537 浏览
提问于 2025-04-17 15:21

正确的语法是什么?

编程尝试

class Foo:
    def hello(self):
        print "Hello cruel world!"
 
    def greet_first(self, f):
        self.hello()
        return lambda *args, **kwargs: f(*args, **kwargs)
 
    @greet_first
    def goodbye(self, concat):
        print "Goodbye {0}".format(concat)
 
if __name__=='__main__':
    bar = Foo()
    bar.goodbye(' and thanks for all the fish')

调试

Traceback (most recent call last):
  File "prog.py", line 1, in <module>
    class Foo:
  File "prog.py", line 9, in Foo
    @greet_first
TypeError: greet_first() takes exactly 2 arguments (1 given)

参考资料

点击这里运行代码(IDEone)

1 个回答

2

装饰器是立即被调用的,它并不是作为Foo类的方法来处理,而是被视为一个局部函数。@greet_first的写法实际上意味着:

 goodbye = greet_first(goodbye)

并且它会立即执行。它不是一个绑定的方法,所以self参数并不包含在内。把greet_first做成一个方法是没有意义的。把它移出去,并完全去掉self参数。

你需要调整你的装饰器,让它返回一个可以调用的东西来替代goodbye

def greet_first(f):
    def wrapper(self, *args, **kwargs):
        self.hello()
        return f(self, *args, **kwargs)
    return wrapper

这样每次调用goodbye的时候,self.hello()都会被调用。

如果你必须greet_first放进Foo里,你可以使用@staticmethod装饰器,但你需要额外做一些步骤才能在其他方法声明中使用它;你需要把它当作一个描述符来处理,并调用.__get__()

class Foo(object):
    def hello(self):
        print "Hello cruel world!"

    @staticmethod
    def greet_first(f):
        def wrapper(self, *args, **kwargs):
            self.hello()
            return f(self, *args, **kwargs)
        return wrapper

    @greet_first.__get__(object)
    def goodbye(self, concat):
        print "Goodbye {0}".format(concat)

我用一个任意的类型(在这个例子中是object)来调用.__get__(),因为staticmethod反正会忽略那个参数;我们不能在这里使用Foo,因为在它的定义代码中,这个类还没有被最终确定。

注意,在Python 2中,要让@staticmethod正常工作,你需要从object继承。

撰写回答