函数装饰器引发位置参数错误?

Function decorator raising positional argument error?

我正在尝试编写一个函数装饰器来测试 x、y 的边界

#this is my bound test function
def boundtest(func):
    def onDecorator(self, x, y, *args, **kwargs):
        print(x, y, *args, **kwargs)
        assert x in range(self.width) and y in range(self.height)
        return func(x, y, *args, **kwargs)

    return onDecorator

class Game:
    #these are the functions that need bound checking

    @boundtest
    def at(self, x: int, y: int) -> int:
        return self.map[x, y]

    @boundtest
    def set(self, x: int, y: int, data):
        self.map[x, y] = data.value

当我执行 game.set(1, 1, Color.RED) 时,我得到:

Traceback (most recent call last):
  File "C:\Users\Ben\Desktop\Projects\bubble-breaker-bot\game.py", line 61, in <module>
    game.set(1, 1, Color.RED)
  File "C:\Users\Ben\Desktop\Projects\bubble-breaker-bot\game.py", line 21, in onDecorator
    return func(x, y, *args, **kwargs)
TypeError: set() missing 1 required positional argument: 'data'

我需要 boundtest 函数来检查 xy 是否分别在 self.widthself.height 范围内,同时能够传递任意数量的它正在装饰的函数的参数。

为什么会这样?

装饰器应用于函数对象,而不是绑定方法。这意味着您需要 手动传递 self 参数:

def boundtest(func):
    def onDecorator(self, x, y, *args, **kwargs):
        print(x, y, *args, **kwargs)
        assert x in range(self.width) and y in range(self.height)
        return func(self, x, y, *args, **kwargs)

    return onDecorator

Python使用一个叫做binding的过程将一个函数变成一个绑定方法,调用一个绑定方法会自动传入绑定的任何东西to 作为第一个参数;这就是当您在实例上调用函数时将 self 传递给方法的方式。请参阅 Descriptor HowTo for details. Instead of manually passing on self, you could invoke descriptor binding manually, by calling func.__get__() 生成绑定方法:

def boundtest(func):
    def onDecorator(self, x, y, *args, **kwargs):
        print(x, y, *args, **kwargs)
        assert x in range(self.width) and y in range(self.height)
        bound_method = func.__get__(self, type(self))
        return bound_method(x, y, *args, **kwargs)

    return onDecorator

game.set 被解析时,该绑定行为应用于装饰器返回的 onDecorator 函数对象,但未应用于包装的 func 对象。