首页 > 解决方案 > 属性装饰器的扩展行为

问题描述

我想扩展内置@property装饰器的行为。所需的用法如下面的代码所示:

class A:
    def __init__(self):
        self.xy = 42

    @my_property(some_arg="some_value")
    def x(self):
        return self.xy

print(A().x) # should print 42

首先,装饰器应该保留属性行为,以便()x. 接下来,我希望能够访问程序员传递给我的装饰器的参数。

我从这个开始:

class my_property(property):
   def __init__(self, fn):
       super().__init__(fn)

TypeError: __init__() got an unexpected keyword argument 'some_arg'

添加后**kwargs

class my_property(property):
   def __init__(self, fn, **kwargs):
       super().__init__(fn)

TypeError: __init__() missing 1 required positional argument: 'fn'

好的,让我们*args改为:

class my_property(property):
   def __init__(self, *args, **kwargs):
       super().__init__(*args)

TypeError: 'my_property' object is not callable

让我们让它可调用:

class my_property(property):
    def __init__(self, *args, **kwargs):
        super().__init__(*args)

    def __call__(self, *args, **kwargs):
        pass

No errors, but prints None instead of 42

现在我迷路了。我什至还没有设法访问 `some_arg="some_value" 并且属性行为似乎已经消失了。出了什么问题以及如何解决?

标签: pythonpropertiesdecorator

解决方案


目前尚不清楚您打算如何使用some_arg,但是要将参数传递给装饰器,您需要有“两层”装饰器

@my_decorator(arg)
def foo():
    return

在引擎盖下,这转化为my_decorator(arg)(foo)(即my_decorator(arg)必须返回另一个用 调用的装饰器foo)。在这种情况下,内部装饰器应该是您自定义的属性实现

def my_property(some_arg):
    class inner(object):
        def __init__(self, func):
            print(some_arg)  # do something with some_arg
            self.func = func

        def __get__(self, obj, type_=None):
            return self.func(obj)
    return inner

现在你可以像这样使用它:

class MyClass:
    def __init__(self, x):
        self.x = x

    @my_property('test!')
    def foo(self):
        return self.x


obj = MyClass(42)  # > test!
obj.foo            # > 42  

在此处阅读有关描述符的更多信息


推荐阅读