You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中能否编写带参数且返回SpecialProperty的装饰器?

实现带参数的SpecialProperty装饰器

当然可以实现既接收额外参数、又返回SpecialProperty实例的装饰器!你的思路方向是对的,只是对带参数装饰器的执行流程有点误解——咱们一步步拆解清楚。

核心原理澄清

当你使用@my_module.make_special_property("example string")这种语法时,Python会先执行make_special_property("example string"),得到一个临时的装饰器函数(就是你代码里的wrapper),然后这个临时函数会接收被装饰的方法get_my_property作为参数,最终返回SpecialProperty实例替换原方法。整个过程结束后,类成员是SpecialProperty对象,完全不是可调用的函数,这完全符合你的需求。

正确实现代码

首先先修正你的SpecialProperty类定义(你之前的代码里有个笔误,把SpecialProperty写成了SerialisableProperty):

class SpecialProperty(property):
    extra_field_1 = None
    extra_field_2 = None

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        super().__init__(fget, fset, fdel, doc)

然后实现带参数的装饰器:

def make_special_property(custom_arg_1):
    # 这个wrapper是临时的装饰器函数,只负责接收被装饰的方法
    def wrapper(func):
        prop = SpecialProperty(fget=func)
        prop.extra_field_1 = custom_arg_1
        # 最终返回的是SpecialProperty实例,替换原方法
        return prop
    # 先返回临时装饰器函数,让Python去调用它处理被装饰的方法
    return wrapper

使用示例

按照你的期望方式使用:

class DeclaringClass:
    def __init__(self):
        self._my_property = "test value"

    @make_special_property("example string")
    def get_my_property(self):
        return self._my_property

验证结果

现在测试一下,完全符合你的要求:

>>> DeclaringClass.get_my_property
<__main__.SpecialProperty object at 0x10a2b3d90>
>>> DeclaringClass.get_my_property.extra_field_1
'example string'
>>> obj = DeclaringClass()
>>> obj.get_my_property
'test value'

进阶:支持多参数和无参数调用

如果你想让装饰器既可以带参数用,也可以像内置property那样不带参数直接用,可以稍微调整一下装饰器的逻辑:

def make_special_property(*args, **kwargs):
    # 情况1:直接传入被装饰的方法(无参数调用)
    if len(args) == 1 and callable(args[0]):
        func = args[0]
        prop = SpecialProperty(fget=func)
        return prop
    # 情况2:传入了自定义参数,返回临时装饰器
    else:
        def wrapper(func):
            prop = SpecialProperty(fget=func)
            if args:
                prop.extra_field_1 = args[0]
            if kwargs.get('extra2'):
                prop.extra_field_2 = kwargs['extra2']
            return prop
        return wrapper

这样两种用法都支持:

# 带参数
@make_special_property("hello", extra2="world")
def get_prop1(self):
    return self._prop1

# 不带参数,和内置property一样用
@make_special_property
def get_prop2(self):
    return self._prop2

你之前代码的问题

你的尝试其实已经很接近正确答案了,只是误解了“返回可调用对象”的问题——中间的wrapper只是装饰器执行流程中的临时函数,它只会被Python自动调用一次,最终替换类成员的是SpecialProperty实例,而不是wrapper本身,所以完全不会出现“类成员是可调用对象”的问题。

内容的提问来源于stack exchange,提问作者korrigan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 10:03:46