第一次使用装饰器,我错过了什么?

Ser*_*ost 2 python

class User:
    def __init__(self):
       self.score = 0
       self.wins = 0
       self.losses = 0


    def tally(self, func):
        def wrapper_function(w):
            print("Wins: {}\nLosses: {}\nTotal Score: {}".format(self.wins, self.losses, self.score))
            return func(w)
        return wrapper_function()

    @tally
    def record_win(self, w=1):
        self.wins += w


user1 = User()
user1.record_win()
Run Code Online (Sandbox Code Playgroud)

我收到的错误是:TypeError: tally() missing 1 required positional argument: 'func'

编辑这篇文章与这里的不同,因为在那篇文章中装饰器函数不是实例方法..我现在看到它增加了一些特殊的要求。

Sha*_*ger 8

您的问题是您正在定义tally为实例方法,但它实际上只是一个装饰器函数(不能以任何合理的方式在实例上调用它)。如果您坚持的话,您仍然可以在类中定义它(它对于实例来说毫无用处),您只需要让它接受单个参数(要包装的函数),而不需要self,并使包装器接受self(同时传递任何提供的参数到包装函数):

class User:
    # ... other methods unchanged ...
    def tally(func):
        def wrapper_function(self, *args, **kwargs):  # Accept self + arbitrary arguments to make decorator useable on more functions
            print("Wins: {}\nLosses: {}\nTotal Score: {}".format(self.wins, self.losses, self.score))
            return func(self, *args, **kwargs)  # Pass along self to wrapped function along with arbitrary arguments
        return wrapper_function                 # Don't call the wrapper function; you have to return it so it replaces the decorated function
    
    @tally
    def record_win(self, w=1):
        self.wins += w

    # Optionally, once tally is no longer needed for new methods, but before dedenting out of class definition, do:
    del tally
    # so it won't stick around to appear as a possible method to call on instances
    # It's done all the work it needs to do after all
Run Code Online (Sandbox Code Playgroud)

删除w支持的参数*args, **kwargs意味着您不需要专门针对特定的函数原型,也不需要复制您正在包装的函数的默认值(如果它们不传递参数,则将自动使用默认值)。