在 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仅在以下情况下调用:
- 描述符在类上定义
- 描述符的名称在所述类的实例上被访问
问题是,在 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 的东西。
