扩展属性装饰器的行为

时间:2019-07-24 13:41:56

标签: python properties decorator

我想扩展内置@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”,并且该属性的行为似乎已经消失了。有什么问题以及如何解决?

1 个答案:

答案 0 :(得分:1)

目前尚不清楚您打算如何使用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  

详细了解descriptors here