自定义类型提示注解
Custom type hint annotation
我刚刚为 Python 编写了一个简单的 @autowired
decorator,它根据类型注释实例化 classes。
为了启用 class 的惰性初始化,该包提供了一个 lazy(type_annotation: (Type, str))
函数,以便调用者可以像这样使用它:
@autowired
def foo(bla, *, dep: lazy(MyClass)):
...
这很好用,在幕后这个 lazy
函数只是 returns 一个 returns 实际类型的函数,并且有一个 lazy_init 属性 设置为 True
。此外,这 不会 破坏 IDE(例如,PyCharm)代码完成功能。
But I want to enable the use of a subscriptable Lazy
type use instead of the lazy
function.
像这样:
@autowired
def foo(bla, *, dep: Lazy[MyClass]):
...
这与 typing.Union 非常相似。 虽然我能够实现可订阅类型,但 IDE 的代码完成功能将变得无用,因为它会在 Lazy
class 中提供属性建议, 不是 MyClass
.
我一直在使用这段代码:
class LazyMetaclass(type):
def __getitem__(lazy_type, type_annotation):
return lazy_type(type_annotation)
class Lazy(metaclass=LazyMetaclass):
def __init__(self, type_annotation):
self.type_annotation = type_annotation
我尝试将 Lazy.__dict__
重新定义为 属性 以转发到下标类型的 __dict__
,但这似乎对 PyCharm 的代码完成功能没有影响。
我坚信我正在努力实现的目标是可能的,因为 typing.Union 与 IDE 的代码完成配合得很好。我一直在尝试破译 typing.Union 的源代码中的哪些内容使其在代码完成功能方面表现良好,但到目前为止没有成功。
要使 Container[Type]
符号起作用,您需要创建一个 user-defined generic type:
from typing import TypeVar, Generic
T = TypeVar('T')
class Lazy(Generic[T]):
pass
然后你使用
def foo(bla, *, dep: Lazy[MyClass]):
和 Lazy
被看作是容纳 class 的容器。
注意:这个仍然意味着IDE将dep
视为Lazy
[=54类型的对象=]. Lazy
这里是一个容器类型,持有一个MyClass
类型的对象。您的 IDE 不会自动完成 MyClass
类型,您不能那样使用它。
该表示法也不会创建 Lazy
class 的实例;它通过 GenericMeta
metaclass 创建了一个 subclass。 subclass 有一个特殊的属性 __args__
让你反省订阅参数:
>>> a = Lazy[str]
>>> issubclass(a, Lazy)
True
>>> a.__args__
(<class 'str'>,)
如果您只想在运行时访问类型注释,但懒惰地解析名称,您可以只支持字符串值:
def foo(bla, *, dep: 'MyClass'):
这是有效的类型注解,和你的装饰器可以在运行时通过使用typing.get_type_hints()
function解析名称(在延迟时间,而不是在装饰时),或者在修饰时将字符串包装在 lazy()
可调用对象中。
如果 lazy()
是为了标记一个类型以区别于其他类型提示,那么您正在尝试用其他含义重载类型提示注释,并简单地键入提示 不支持此类用例,并且使用 Lazy[...]
包含无法使其工作。
我刚刚为 Python 编写了一个简单的 @autowired
decorator,它根据类型注释实例化 classes。
为了启用 class 的惰性初始化,该包提供了一个 lazy(type_annotation: (Type, str))
函数,以便调用者可以像这样使用它:
@autowired
def foo(bla, *, dep: lazy(MyClass)):
...
这很好用,在幕后这个 lazy
函数只是 returns 一个 returns 实际类型的函数,并且有一个 lazy_init 属性 设置为 True
。此外,这 不会 破坏 IDE(例如,PyCharm)代码完成功能。
But I want to enable the use of a subscriptable Lazy
type use instead of the lazy
function.
像这样:
@autowired
def foo(bla, *, dep: Lazy[MyClass]):
...
这与 typing.Union 非常相似。 虽然我能够实现可订阅类型,但 IDE 的代码完成功能将变得无用,因为它会在 Lazy
class 中提供属性建议, 不是 MyClass
.
我一直在使用这段代码:
class LazyMetaclass(type):
def __getitem__(lazy_type, type_annotation):
return lazy_type(type_annotation)
class Lazy(metaclass=LazyMetaclass):
def __init__(self, type_annotation):
self.type_annotation = type_annotation
我尝试将 Lazy.__dict__
重新定义为 属性 以转发到下标类型的 __dict__
,但这似乎对 PyCharm 的代码完成功能没有影响。
我坚信我正在努力实现的目标是可能的,因为 typing.Union 与 IDE 的代码完成配合得很好。我一直在尝试破译 typing.Union 的源代码中的哪些内容使其在代码完成功能方面表现良好,但到目前为止没有成功。
要使 Container[Type]
符号起作用,您需要创建一个 user-defined generic type:
from typing import TypeVar, Generic
T = TypeVar('T')
class Lazy(Generic[T]):
pass
然后你使用
def foo(bla, *, dep: Lazy[MyClass]):
和 Lazy
被看作是容纳 class 的容器。
注意:这个仍然意味着IDE将dep
视为Lazy
[=54类型的对象=]. Lazy
这里是一个容器类型,持有一个MyClass
类型的对象。您的 IDE 不会自动完成 MyClass
类型,您不能那样使用它。
该表示法也不会创建 Lazy
class 的实例;它通过 GenericMeta
metaclass 创建了一个 subclass。 subclass 有一个特殊的属性 __args__
让你反省订阅参数:
>>> a = Lazy[str]
>>> issubclass(a, Lazy)
True
>>> a.__args__
(<class 'str'>,)
如果您只想在运行时访问类型注释,但懒惰地解析名称,您可以只支持字符串值:
def foo(bla, *, dep: 'MyClass'):
这是有效的类型注解,和你的装饰器可以在运行时通过使用typing.get_type_hints()
function解析名称(在延迟时间,而不是在装饰时),或者在修饰时将字符串包装在 lazy()
可调用对象中。
如果 lazy()
是为了标记一个类型以区别于其他类型提示,那么您正在尝试用其他含义重载类型提示注释,并简单地键入提示 不支持此类用例,并且使用 Lazy[...]
包含无法使其工作。