簡體   English   中英

如何定義自定義無操作特殊表單類型

[英]How to define a custom no-op special form type

我需要一些行為如下:

NoOp = ...  # don't know how to define this

def foo(bar: NoOp[int]) -> int:
    return bar + 1

foo(1)

我希望 mypy 將bar完全視為我只是將其注釋為bar: int 我還需要它與int本身不同,以便編寫代碼來檢查是否用例如NoOp[str]而不是str注釋了某些內容。 只是 mypy 應該對它們一視同仁。


我嘗試使用NewType來獲得類似的東西,但是由於它將生成的定義視為子類,因此不適用於我的目的,而且我必須使用它的方式也創建了很難閱讀的代碼。

如果我理解正確, NoOp[T]T在運行時和類型檢查器的眼中都是完全相同的類型。 唯一的區別是您要編寫檢查注釋的自定義代碼,並且能夠將TNoOp[T]分開來。 這個對嗎?

如果是這樣,那么您可以查看在 Python 3.9 中引入並通過typing_extensions移植的Annotated類型。 它采用Annotated[T, X]的形式,其中T是類型注釋, X是任意元數據。 它允許您將元數據X與注釋T相關聯,同時不更改類型(即Annotated[T, X]等效於T )。

對於您的情況,您可以將NoOp定義為泛型類型別名:

T = TypeVar("T")
NoOp = Annotated[T, "no-op"]  # use "no-op" as metadata, but you could just choose any value

def foo(bar: NoOp[int]) -> int:
    return bar + 1

然后,您可以使用typing.get_type_hints檢查注釋(對於 3.9 之前的版本,將typing替換為typing_extensions )。 注釋對象將具有__metadata__屬性,該屬性包含元數據的元組:

>>> typing.get_type_hints(foo)  # by default it strips the metadata
{'x': int, 'return': int}

>>> typing.get_type_hints(foo, include_extras=True)
{'x': typing.Annotated[int, 'no-op'], 'return': int}

>>> x_annotation = typing.get_type_hints(foo, include_extras=True)["x"]
>>> x_annotation.__metadata__
('no-op',)

它是一個元組的原因是因為您可以將多個值與其關聯,例如Annotated[int, "a", "b", 1.234]

有一些疑問,因為我不確定我是否得到了你的用例——如果這不是你需要的,對不起。

from typing import Generic, TypeVar

T = TypeVar('T')   # you can better specify this if needed

class Wrapper(Generic[T]):
    def __init__(content: T):
    self.content = content


def f(x: Wrapper[int] | int) -> int:
    if isinstance(x, Wrapper): 
        return x.content + 1
    return x + 1

另一方面,如果您想讓Wrapper以函數方式運行,這樣您就不需要在f中進行實例檢查,您可以執行類似的操作

    def __add__(self, other: Wrapper[T] | T):
        if isinstance(other, Wrapper):
            return Wrapper(self.content + other.content)
        return Wrapper(self.content + other)

但是你需要小心,因為你最終會得到一個非交換的__add__ (不一定是錯誤的,但需要注意一些事情)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM