考虑用Python编写一个接口类。接口将getter和setter方法隐藏在属性后面。有几个属性具有非常相似的结构,只是名称不同。为了减少代码重复,接口为其属性使用工厂方法:
from __future__ import annotations
class Interface:
def property_factory(name: str) -> property:
"""Create a property depending on the name."""
@property
def _complex_property(self: Interface) -> str:
# Do something complex with the provided name
return name
@_complex_property.setter
def _complex_property(self: Interface, _: str):
pass
return _complex_property
foo = property_factory("foo") # Works just like an actual property
bar = property_factory("bar")
def main():
interface = Interface()
interface.foo # Is of type '(variable) foo: Any' instead of '(property) foo: str'
if __name__ == "__main__":
main()
字符串
这个实现的一个问题是,Interface.foo
和Interface.bar
将被标记为(variable) foo/bar: Any
,即使它们应该是(property) foo/bar: str
。
使用内联类型提示,如
foo: str = property_factory("foo")
型
感觉有点误导,因为foo不是一个真正的字符串。
我并不完全坚持这种属性模式。如果有更好的方法来创建属性,我也很乐意改变这种模式。但是,请记住,接口需要属性,因为真实的代码在getter/setter方法中做更复杂的事情。此外,我希望保留属性,而不是像get_property(self,name:str)这样的通用方法。
我也可以分享我正在处理的实际代码,上面的例子只是我想到的一个最小的例子。
3条答案
按热度按时间cvxl0en21#
疯狂的猜测:
property_factory
被类型提示返回property
;修饰的方法/函数的类型丢失,这通常不会发生,因为类型检查器也会检查它是否在类的主体中使用。property
is not generic(yet)。然而,链接问题的OP本身提供了一个property
的泛型子类作为可能的解决方案。那是将近4年前的事情了,当时类型系统并不像现在这样好,所以让我们重写这个类:字符串
现在我们有了一个通用的
property
类,原始的设计可以重写为:(The原创作品也是,只需要使用
-> Property[Interface, str]
/return Property(_getter, _setter)
。型
.然后可以用作:
型
假设
bar
是同一类的普通@property
,下面是一些测试(mypy playground,pyright playground):型
k10s72fa2#
如果你不需要太多的特殊属性能力,你可以对任何变量、属性或属性使用类型提示,如下所示:
字符串
在某些编辑器中,包括VSCode,您也可以在变量、属性或属性之后添加文档字符串。
(This总是有效的Python,但不是所有的编辑器都知道将文档字符串与变量/属性/属性相关联。尝试一下,看看它是否能在编辑器中工作。
型
下面是它在我的VSCode版本中的样子:x1c 0d1x
balp4ylt3#
在您当前的实现中,出现此问题是因为类型提示系统无法将property_factory创建的属性识别为具有特定类型的属性。解决此问题的一种方法是使用typing.cast函数将属性显式转换为所需类型。这样,您可以提供更准确的类型提示。
以下是如何修改代码:
字符串
在此修改中,我添加了cast(property,_complex_property)行,以显式地将创建的属性转换为属性类型。这允许您将foo和bar的类型提示指定为str。
虽然这解决了类型提示问题,但值得注意的是,使用强制转换本质上是告诉类型检查器信任您的Assert。因此,请确保实际实现符合指定的类型,以避免潜在的运行时错误。