Skip to main content
 首页 » 编程设计

python之在函数上定义@property

2025年05月04日23jillzhang

在 JavaScript 中,我们可以对任何对象或函数执行以下操作

const myFn = () => {}; 
Object.defineProperties(myFn, { 
    property: { 
        get: () => console.log('property accessed') 
    } 
}); 

这将通过为属性 property 定义一个 getter 函数来允许类似 @property 的语法。

myFn.property 
// property accessed 

Python 中的函数 是否有类似的东西? 我知道我们不能使用 property因为它不是新式类,所以用 setattr 分配 lambda 将不起作用,因为它将是一个函数。

基本上我想要实现的是每当 my_fn.property 是在每次调用时返回另一个类的新实例。 我目前拥有的 setattr 是这样的

setattr(my_fn, 'property', OtherClass()) 

我希望设计一个类似于 my_fn.property.some_other_function() 的 API。

我更喜欢将函数用作 my_fn 而不是类的实例,尽管我意识到它可能更容易实现。

下面是我想要实现的要点

def my_fn(): 
    pass 
 
my_fn = property('property', lambda: OtherClass()) 
my_fn.property 
// will be a new instance of OtherClass on each call 

请您参考如下方法:

不可能完全按照您的意愿行事。 The descriptor protocol权力the property built-in仅在以下情况下调用:

  1. 描述符在类上定义
  2. 描述符的名称在所述类的实例上被访问

问题是,在 Python 中定义的函数背后的类(恰本地命名为 function,exposed directly as types.FunctionType 或通过在 Python 层定义的任何函数上调用 type() 间接调用) 是一个共享的、不可变的类,因此您不能向它添加描述符(即使可以,它们也会成为每个 Python 级别函数的属性,而不仅仅是一个特定函数)。

最接近您尝试的方法是定义一个可调用的类(定义__call__),它也定义了您感兴趣的描述符.创建该类的单个实例(此时您可以丢弃该类本身),它的行为将如您所愿。使 __call__ 成为 staticmethod,您将避免更改启动签名。

例如,您想要的行为可以通过以下方式实现:

class my_fn: 
    # Note: Using the name "property" for a property has issues if you define 
    # other properties later in the class; this is just for illustration 
    @property 
    def property(self): 
        return OtherClass() 
    @staticmethod 
    def __call__(...whatever args apply; no need for self...): 
        ... function behavior goes here ... 
my_fn = my_fn()  # Replace class with instance of class that behaves like a function 

现在您可以调用“函数”(实际上是一个仿函数,用 C++ 的说法):

my_fn(...) 

或访问该属性,每次都获得一个全新的OtherClass:

>>> type(my_fn.property) is type(my_fn.property) 
True 
>>> my_fn.property is my_fn.property 
False 

不,这不是您要求的(您似乎打算让一个简单的函数为您执行此操作),但您要求的是 Python 中不存在的非常特定于 JavaScript 的东西。