【问题标题】:Function decorator raising positional argument error?函数装饰器引发位置参数错误?
【发布时间】:2019-01-02 18:47:32
【问题描述】:

我正在尝试编写一个函数装饰器来测试 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 的范围内,同时能够将任意数量的参数传递给它正在装饰的函数。

为什么会这样?

【问题讨论】:

    标签: python python-3.x decorator python-decorators


    【解决方案1】:

    装饰器应用于函数对象,而不是绑定方法。这意味着您需要手动传递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 的进程将函数转换为绑定方法,并且调用绑定方法会自动将其绑定 的任何内容作为第一个参数传入;当您在实例上调用函数时,这就是 self 传递给方法的方式。有关详细信息,请参阅Descriptor HowTo。除了手动传递self,您还可以通过invoke descriptor binding manually 调用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 对象。

    【讨论】:

    • @heemayl:我添加了通常的说明以及文档链接。
    • 有没有更好的方法来编写装饰器?在 PEP 20 之后,python 的禅宗“简单胜于复杂。扁平胜于嵌套。”如果你问我,嵌套函数似乎有点讨厌。
    • @BenjaminKosten:不知道你为什么这么认为。装饰器应该返回原始函数或替换对象。生成重用原始替换的最简单和最简单的方法是使用嵌套函数对象,然后可以访问原始作为闭包。额外的好处是生成的函数对象是唯一的;您可以而且应该使用@functools.wraps(func) 复制识别信息。装饰器极大地帮助您简化其余代码!
    • @BenjaminKosten:但是,如果您认为decorator project 会为您生成更清晰的代码,则可以查看。
    猜你喜欢
    • 2021-02-22
    • 2018-01-28
    • 1970-01-01
    • 2023-03-31
    • 2014-07-21
    • 2011-06-25
    • 2020-09-20
    • 2021-12-08
    • 1970-01-01
    相关资源
    最近更新 更多