簡體   English   中英

如何鍵入提示容器子類始終包含特定類型?

[英]How to type-hint that container subclass always contains particular type?

對於 PyCharm 中自定義容器子類的內容類型,我正在努力讓類型提示正常工作。 讓我們從一個符合我預期的案例開始。 您可以創建list的子類並指定它始終具有int內容,然后 Pycharm 會識別出此類列表中的每個項目都是int

class IntList(list[int]): pass
il = IntList(())
answer1 = il[0]

當我將鼠標懸停在answer1上時,Pycharm 說它希望它具有int類型,大概是因為類聲明指定IntList不會是任何舊的list ,而是會是list[int] (不要介意這個代碼在運行時會引發錯誤,因為il會是空的。這只是一個最小的例子,表明 PyCharm 有時可以從類聲明中的括號[int]中提取類型提示信息。同樣在從容器中獲取項目不會引發錯誤的其他情況下會出現問題。)

因此,當從list子類化時,這工作得很好。 但我想做的是創建我自己的通用容器類——稱之為Box它可以包含各種不同類型的對象。 然后我想聲明我自己的子類IntBox ,它只包含int項,我希望 PyCharm 在其各種鼠標懸停提示、自動完成建議和 linting 錯誤檢測中識別這一點,就像它對IntList 所以這是我想要的一個非常精簡的例子。

class Box(list): pass
class IntBox(Box[int]): pass
ib = IntBox(())
answer2 = ib[0]

在這種情況下,當我將鼠標懸停在answer2上時,PyCharm 說它可能具有類型Any並且不承認[int]暗示這不僅僅是一個通用的 Box/list,而是一個其內容已被類型提示的成為int

我已經嘗試了所有可以想象的變體,使用typing.TypeVartyping.Generic來嘗試更明確地表明Box的每個子類將具有單一類型的內容, Box.__getitem__將返回該類型,並且對於類型為int的子類IntBox

我發現的唯一解決方案是,當我創建ib時,我可以顯式聲明此實例的類型為IntBox[int] ,然后 PyCharm 將知道期望ib[0]將是一個int 但似乎我不需要每次創建一個IntBox實例時都明確地說,而是應該有某種方法讓 PyC​​harm 從IntBox的類聲明中的[int]推斷這一點,就像它可以IntList

當然,這只是一個玩具示例。 在激發這一點的真實案例中,我希望我的通用容器類“Box”定義類型提示的其他方法(不僅僅是__getitem__ )以返回相關“Box”的子類始終包含的任何特定類型的對象,其中這因子類而異。 使用TypeVarGeneric我可以讓它工作,如果我明確地類型聲明每個子類實例將包含一個特定的[contenttype] ,但是如果沒有繁瑣的顯式類型聲明,我找不到讓它工作的方法每個實例。

編輯:由於在簡單的情況下工作的解決方案告訴list子類中的元素顯然不會自動擴展到這個真實情況,這里有一個更接近我需要的例子,包括那個Box是一個嵌套的Sequence而不是一個簡單的list ,包括一個Box.get_first()方法,它也應該接收IntBoxint類型提示,並且包括我認為大致正確使用TypeVar的方法:

from typing import TypeVar, Sequence
T = TypeVar('T')
class Box(Sequence[Sequence[T]]):
    def get_first(self:'Box[T]')->T:
        return self[0][0]
class IntBox(Box[int]): pass
ib = IntBox()  # works only if I declare this is type: IntBox[int]
answer = ib.get_first()  # hovering over answer should show it will be int

進一步編輯:前面的問題似乎是嵌套的Sequence[Sequence[T]] 將其更改為Generic[T]會使事情按預期工作。

使用typing.Generic將類型從使用typing.TypeVar的子類傳遞給Box超類

from typing import Generic, TypeVar

T = TypeVar('T')


class Box(Generic[T], list[T]):
    pass


class IntBox(Box[int]):
    pass


class StrBox(Box[str]):
    pass


ib = IntBox(())
answer1 = ib[0]  # int
sb = StrBox(())
answer2 = sb[0]  # str

暫無
暫無

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

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