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

如何在Python函数上实现类似JavaScript的@property特性?

在Python中为函数实现动态属性Getter

好问题!在Python里给函数实现类似JavaScript中动态getter的效果确实需要绕个小弯——因为Python的property装饰器默认是为类设计的,而函数本身是function类的实例,没法直接用常规的property语法实现动态属性。不过我们有两种优雅的方式达成你的需求,既能保持my_fn的函数特性(可以正常调用),又能让每次访问my_fn.property都返回新的OtherClass实例。

方法一:继承function类扩展功能

Python的函数本质上是function类的实例,我们可以创建一个function的子类,在子类中定义property属性来实现动态Getter。这种方式能让my_fn保留函数的类型特性(isinstance(my_fn, function)会返回True)。

完整代码示例

class OtherClass:
    def some_other_function(self):
        print("调用了新OtherClass实例的some_other_function方法")

# 继承function类,添加动态property
class FunctionWithDynamicProperty(function):
    @property
    def property(self):
        # 每次访问都返回新的OtherClass实例
        return OtherClass()

# 定义原函数
def my_fn():
    print("原my_fn函数被调用")

# 将原函数转换为自定义子类的实例
my_fn = FunctionWithDynamicProperty(my_fn)

测试效果

# 正常调用函数
my_fn()  # 输出:原my_fn函数被调用

# 每次访问property都得到新实例
instance1 = my_fn.property
instance2 = my_fn.property
print(instance1 is instance2)  # 输出:False

# 链式调用方法
my_fn.property.some_other_function()  # 输出:调用了新OtherClass实例的some_other_function方法

方法二:用包装器类模拟函数行为

如果不想继承function类,我们可以用组合的方式创建一个包装器,通过实现__call__方法让包装器对象可以像函数一样被调用,同时用__getattr__方法处理动态属性的访问。这种方式更灵活,适合需要添加多个动态属性的场景。

完整代码示例

class OtherClass:
    def some_other_function(self):
        print("调用了新OtherClass实例的some_other_function方法")

class FunctionWrapper:
    def __init__(self, func):
        # 复制原函数的所有属性,保持函数的原有特性(比如__name__、__doc__等)
        self.__dict__.update(func.__dict__)
        self._func = func

    def __call__(self, *args, **kwargs):
        # 让包装器可以像原函数一样被调用
        return self._func(*args, **kwargs)

    def __getattr__(self, name):
        # 处理动态属性访问
        if name == "property":
            return OtherClass()
        # 其他属性直接转发给原函数
        return getattr(self._func, name)

# 定义原函数
def my_fn():
    print("原my_fn函数被调用")

# 用包装器包裹原函数
my_fn = FunctionWrapper(my_fn)

测试效果

和方法一完全一致,包装后的my_fn可以正常调用,且每次访问property都会返回新的OtherClass实例。

为什么你的初始尝试不行?

你之前用setattr(my_fn, 'property', OtherClass())的方式,只会在赋值时创建一次OtherClass实例,之后每次访问my_fn.property都是同一个实例——因为赋值语句执行时OtherClass()就已经被调用并生成实例了。

而Python的property装饰器是基于描述符协议实现的,它需要定义在类的命名空间中才能生效;直接给函数实例(function类的对象)赋值property对象,只会把它当作普通属性存储,不会触发getter逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:39:08