簡體   English   中英

Python 中的受限泛型類型提示

[英]Restricted generic type hint in Python

我想創建一個像這里這樣的工廠方法。

class A:
    ...

class B(A):
    def f(self):
        ...

class C:
    ...

def factory(cls):
    return cls()

但我想添加一些具有兩個要求的類型提示:

  • 只允許A子類作為factory參數。
  • B通過,它被正確地將檢測到factory(B)是實例B ,即。 factory(B).f()是允許的,而factory(A).f()不是。

嘗試 1

使用來自typing模塊的Type

from typing import Type

class A:
    ...

class B(A):
    def f(self):
        ...

class C:
    ...

def factory(cls: Type[A]):
    return cls()

factory(A)  # Ok
factory(B)  # Ok
factory(C)  # Fail
factory(A).f()  # Fail
factory(B).f()  # Fail -- Wrong!

這個正確地檢測到C不應該作為factory參數傳遞。 但是,類型檢查器不允許factory(B).f()

嘗試 2

使用類型TypeVar

from typing import TypeVar, Type
T = TypeVar('T')

class A:
    ...

class B(A):
    def f(self):
        ...

class C:
    ...

def factory(cls: Type[T]) -> T:
    return cls()

factory(A)  # Ok
factory(B)  # Ok
factory(C)  # Ok -- Wrong!
factory(A).f()  # Fail
factory(B).f()  # Ok

可以很好地推斷出factory(B).f()很好,而factory(A).f()不是。 但是,泛型沒有限制,即。 工廠(C)也可以。

嘗試 3

T添加約束。

from typing import TypeVar, Type

class A:
    ...

class B(A):
    def f(self):
        ...

class D(A):
    ...

class C:
    ...

T = TypeVar('T', A)
def factory(cls: Type[T]) -> T:
    return cls()


factory(A)  # Ok
factory(B)  # Ok
factory(C)  # Fail
factory(A).f()  # Fail
factory(B).f()  # Ok

這看起來很有希望,至少 PyCharm 可以正確處理所有情況。 但是對於實際使用而言,這種解決方案實際上是最糟糕的 - A single constraint is not allowed出現A single constraint is not allowed錯誤,但尚不清楚原因。 在 PEP 484 中,只有簡短的一行說“應該至少有兩個約束,如果有的話; 不允許指定單個約束。

對此有什么好的解決方案嗎? 我只有一些東西,比如添加一個“虛擬”類_A ,一個空白的A子類,並將其作為另一個約束來擁有這樣的東西。

_A = NewType('_A', A)
T = TypeVar('T', A, _A)
def factory(cls: Type[T]) -> T:
    return cls()

但我真的不認為這是一個很好的解決方案。

先感謝您!

使用TypeVarbound似乎工作:

from typing import Type, TypeVar

class A:
    ...

class B(A):
    def f(self):
        ...

class C:
    ...

AnyA = TypeVar("AnyA", bound=A)

def factory(cls: Type[AnyA]) -> AnyA:
    return cls()


factory(A).f()  # error: "A" has no attribute "f"
factory(B).f()  # ok!
factory(C)      # error: Value of type variable "AnyA" of "factory" cannot be "C"

關於TypeVar的文檔說:

...類型變量可以使用bound=<type>指定上限。 這意味着替換(顯式或隱式)類型變量的實際類型必須是邊界類型的子類

這看起來和你想要的完全一樣,所以你可以寫:

T = TypeVar('T', bound=A)

暫無
暫無

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

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