简体   繁体   English

Python3 无法将 @property 作为装饰器参数传递

[英]Python3 impossible to pass @property as decorator argument

I've implemented decorator that can receive extra arguments and want to use it with class methods.我已经实现了可以接收额外的 arguments 并希望将其与 class 方法一起使用的装饰器。 I want to pass @property as decorator argument, but instead of @property result I got this:我想将@property 作为装饰器参数传递,但我得到的不是@property 结果:

<property object at 0x7f50f5195230>

This is my decorator:这是我的装饰器:

class Decorator(object):
    def __init__(self, some_arg):
        self.func = None
        self.some_arg = some_arg

    def __get__(self, instance, owner):
        import functools
        return functools.partial(self.__call__, instance)

    def __call__(self, func):
        self.func = func
        def wrapper(*args, **kwargs):
            return self._process_sync(*args, **kwargs)
        return wrapper

    def _process_sync(self, *args, **kwargs):
        try:
            print(self.some_arg)
            return self.func(*args, **kwargs)
        except Exception as e:
            print(e)
            return None

My test class:我的测试 class:

class Test(object):
    @property
    def some_data(self):
        return {'key': 'value'}

    @Decorator(some_data)
    def some_method(self):
        print('method output')
        return None

Usage:用法:

test = Test()
test.some_method()

Two questions:两个问题:

  1. How to correctly pass property to receive @property result instead of <property object at 0x7f50f5195230>如何正确传递属性以接收 @property 结果而不是<property object at 0x7f50f5195230>
  2. Does it possible to pass class properties/methods to the decorator if they are below in code?如果 class 属性/方法在代码下方,是否可以将它们传递给装饰器?

A property object is a descriptor. property object 是一个描述符。 To get a value out of it, you need to call its __get__ method with an appropriate instance.要从中获取值,您需要使用适当的实例调用其__get__方法。 Figuring out when to do that in your current code is not easy, since your Decorator object has a bunch of different roles.在您当前的代码中确定何时执行此操作并不容易,因为您的Decorator object 有很多不同的角色。 It's both a decorator factory (getting initialized with an argument in the @Decorator(x) line), and the decorator itself (getting called with the function to be decorated).它既是装饰器工厂(使用@Decorator(x)行中的参数进行初始化),又是装饰器本身(使用 function 进行装饰)。 You've given it a __get__ method, but I don't expect that to ever get used, since the instance of Decorator never gets assigned to a class variable (only the wrapper function that gets returned from __call__ ).你给了它一个__get__方法,但我不希望它被使用,因为Decorator的实例永远不会被分配给 class 变量(只有从__call__返回的包装器 function )。

Anyway, here's a modified version where the Decorator handles almost all parts of the descriptor protocol itself:无论如何,这是一个修改后的版本,其中Decorator处理了描述符协议本身的几乎所有部分:

class Decorator:
    def __init__(self, arg):
        self.arg = arg      # this might be a descriptor, like a property or unbound method

    def __call__(self, func):
        self.func = func
        return self         # we still want to be the descriptor in the class

    def __get__(self, instance, owner):
        try:
            arg = self.arg.__get__(instance, owner)   # try to bind the arg to the instance
        except AttributeError: # if it doesn't work, self.arg is not a descriptor, that's OK
            arg = self.arg

        def wrapper(*args, **kwargs):   # this is our version of a bound method object
            print(arg) # do something with the bound arg here
            return self.func.__get__(instance, owner)(*args, **kwargs)

        return wrapper

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM