有没有一种方法可以在模块级别调用时将函数注释为类型,但在类内部时显示其属性值?

问题描述 投票:0回答:1

在开发项目时,我偶然发现了返回自定义属性对象时键入注释的问题。

这是代表问题的代码片段:

from typing import TypeVar, Any

_B = TypeVar("_B")

class CustomProperty(property):
    def a_function(): ...

def custom_property(type: _B) -> _B:
    return CustomProperty(type)

custom_property(int).a_function()  # As passed int, typing shows it as an int when I expect CustomProperty

class ClassWithCustomProperty:

    property_holder = custom_property(int)  # This shows as an int, correct

在上面的代码中,custom_property 返回 CustomProperty 的实例,custom_property 可以在类内部(充当属性)和模块级别(充当 CustomProperty 实例)使用

  • 我应该如何注释 custom_property 函数,使其在模块级别调用时显示 CustomProperty 类型,并在类内部显示 int ?这可能吗?

在此项目中,使用 custom_property/CustomProperty 作为装饰器不是有效选项。

我尝试过使用

Union[_B, CustomProperty]
但得到
type[int] | CustomProperty
这并不理想,因为我期望在模块级别调用时
CustomProperty
以及在类内调用时
type[int]

提前感谢您,如果有任何不清楚或需要更多背景信息,请随时添加评论。

python python-typing
1个回答
0
投票

如果我理解正确的话,这将是期望的结果:

module_level = custom_property(int)
reveal_type(module_level)                               # CustomProperty[int]
reveal_type(module_level.a_function())                  # int

class ClassWithCustomProperty:
    property_holder = custom_property(int)
    reveal_type(property_holder)                        # CustomProperty[int]

reveal_type(ClassWithCustomProperty.property_holder)    # CustomProperty[int]
reveal_type(ClassWithCustomProperty().property_holder)  # int

为此,请使

CustomProperty
通用并重载
.__get__()
:

(游乐场链接:PyrightMypy

class CustomProperty[T](property):
    @overload
    def __get__(self, instance: None, owner: type[Any] | None, /) -> Self: ...

    @overload
    def __get__(self, instance: Any, owner: type[Any] | None, /) -> T: ...

    def __get__(self, instance: Any, owner: type[Any] | None = None) -> T | Self:
        return super().__get__(instance, owner)

    def a_function(self) -> T: ...

def custom_property[T](type: type[T]) -> CustomProperty[T]:
    return CustomProperty(type)
当从类 (

instance

) 访问描述符(即 
None
)或根本不存在这样的类/实例 (
CustomProperty
) 时,
C.property_holder
module_level
,在这种情况下我们返回描述符对象(即
CustomProperty[T]
/
Self
)。

否则,描述符是从实例访问的(

C().property_holder
),因此我们返回包含的值(即
T
)。

© www.soinside.com 2019 - 2024. All rights reserved.