如何让 IDE 识别 Python 中静态声明、动态创建的类所需的类型名称?

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

问题:

我正在开发一个库,例如,支持 UInt5 类型、Int33 类型等。该库比这更复杂一些,但为了举例说明,可能会创建一个 UInt12 类型

def makeUInt(size:int) -> type[UInt]:
   class NewUInt(UInt):
       # Do stuff with size
   NewUInt.__name__ = f"UInt{size}"
   return NewUInt
   
UInt12 = makeUInt(12)
an_example_number = UInt12(508)

我的 IDE (VS Code) IntelliSense 功能会将 an_example_number 的类型识别为 UInt,而不是 UInt12。

摩擦:

我不希望通过类型提示来选择动态声明的类型。然而,我已经明确指定 UInt12 作为类型别名,事实上,如果我通过子类化而不是类型别名

def makeUInt(size:int) -> type[UInt]:
   class NewUInt(UInt):
       # Do stuff with size
   NewUInt.__name__ = f"UInt{size}"
   return NewUInt
   
class UInt12(makeUInt(12)): pass
an_example_number = UInt12(508)

一切都按预期运行,因此在某种程度上,动态声明显然可以被强制转换为 IDE 可以理解的内容。

例如,假设我可以让 UInt 保留已创建类的寄存器,并防止 UInt12(makeUInt(12)) 实际进行子类化。但这显然不是一个理想的解决方法。

询问:

如何(最好在 Python 3.8 中)保留动态创建类型的优势,同时让 IDE 了解我对这些类型实例的首选命名法?

最终用例是我想显式提供某些类型,而不需要每次都重新声明 # Do stuff with size information,这样像 UInt16、UInt32 等常见类型就可以在我的库中声明并接收提示,而更多像 UInt13 这样的不常见类型将由用户根据需要声明,并且不一定会收到提示。

开箱即用

def makeUInt(size:int) -> type[UInt]:
   class NewUInt(UInt):
       # Do stuff with size
   NewUInt.__name__ = f"UInt{size}"
   return NewUInt
   
UInt12 = makeUInt(12)
an_example_number = UInt12(508)

我希望 an_example_number 通过类型提示显示为 UInt12。它显示为 UInt。

python python-typing metaclass type-alias
1个回答
0
投票

正如您所见,创建子类可能会在您的情况下效果更好。

不要创建类工厂函数,而是在基类中定义所有派生类的共同行为,并使具体行为取决于子类定义的类变量。

在与您的示例类似的示例中,这可能如下所示:

class UInt:
    size: int  # to be defined by subclasses

    def __init__(self, value: int):
        if value >= 2 ** self.size:
            raise ValueError("Too big")
        self._value = value

    def __repr__(self):
        return f"{self.__class__.__name__}({self._value})"


class UInt12(UInt):
    size = 12


an_example_number = UInt12(508)
print(repr(an_example_number))
© www.soinside.com 2019 - 2024. All rights reserved.